63 Star 180 Fork 3

Gitee 极速下载 / hyperledger-fabric

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
此仓库是为了提升国内下载速度的镜像仓库,每日同步一次。 原始仓库: https://github.com/hyperledger/fabric
克隆/下载
lifecycle.go 27.05 KB
一键复制 编辑 原始数据 按行查看 历史
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661
/*
Copyright IBM Corp. All Rights Reserved.
SPDX-License-Identifier: Apache-2.0
*/
package lifecycle
import (
"bytes"
"fmt"
"sync"
cb "github.com/hyperledger/fabric-protos-go/common"
"github.com/hyperledger/fabric-protos-go/msp"
pb "github.com/hyperledger/fabric-protos-go/peer"
lb "github.com/hyperledger/fabric-protos-go/peer/lifecycle"
"github.com/hyperledger/fabric/common/chaincode"
"github.com/hyperledger/fabric/common/flogging"
"github.com/hyperledger/fabric/common/policydsl"
"github.com/hyperledger/fabric/core/chaincode/persistence"
"github.com/hyperledger/fabric/core/container"
"github.com/hyperledger/fabric/protoutil"
"github.com/golang/protobuf/proto"
"github.com/pkg/errors"
)
var logger = flogging.MustGetLogger("lifecycle")
const (
// NamespacesName is the prefix (or namespace) of the DB which will be used to store
// the information about other namespaces (for things like chaincodes) in the DB.
// We want a sub-namespaces within lifecycle in case other information needs to be stored here
// in the future.
NamespacesName = "namespaces"
// ChaincodeSourcesName is the namespace reserved for storing the information about where
// to find the chaincode (such as as a package on the local filesystem, or in the future,
// at some network resource). This namespace is only populated in the org implicit collection.
ChaincodeSourcesName = "chaincode-sources"
// ChaincodeDefinitionType is the name of the type used to store defined chaincodes
ChaincodeDefinitionType = "ChaincodeDefinition"
// FriendlyChaincodeDefinitionType is the name exposed to the outside world for the chaincode namespace
FriendlyChaincodeDefinitionType = "Chaincode"
// DefaultEndorsementPolicyRef is the name of the default endorsement policy for this channel
DefaultEndorsementPolicyRef = "/Channel/Application/Endorsement"
)
var (
DefaultEndorsementPolicyBytes = protoutil.MarshalOrPanic(&pb.ApplicationPolicy{
Type: &pb.ApplicationPolicy_ChannelConfigPolicyReference{
ChannelConfigPolicyReference: DefaultEndorsementPolicyRef,
},
})
)
// Sequences are the underpinning of the definition framework for lifecycle.
// All definitions must have a Sequence field in the public state. This
// sequence is incremented by exactly 1 with each redefinition of the
// namespace. The private state org approvals also have a Sequence number
// embedded into the key which matches them either to the vote for the commit,
// or registers approval for an already committed definition.
//
// Public/World DB layout looks like the following:
// namespaces/metadata/<namespace> -> namespace metadata, including namespace type
// namespaces/fields/<namespace>/Sequence -> sequence for this namespace
// namespaces/fields/<namespace>/<field> -> field of namespace type
//
// So, for instance, a db might look like:
//
// namespaces/metadata/mycc: "ChaincodeDefinition"
// namespaces/fields/mycc/Sequence 1 (The current sequence)
// namespaces/fields/mycc/EndorsementInfo: {Version: "1.3", EndorsementPlugin: "builtin", InitRequired: true}
// namespaces/fields/mycc/ValidationInfo: {ValidationPlugin: "builtin", ValidationParameter: <application-policy>}
// namespaces/fields/mycc/Collections {<collection info>}
//
// Private/Org Scope Implcit Collection layout looks like the following
// namespaces/metadata/<namespace>#<sequence_number> -> namespace metadata, including type
// namespaces/fields/<namespace>#<sequence_number>/<field> -> field of namespace type
//
// namespaces/metadata/mycc#1: "ChaincodeParameters"
// namespaces/fields/mycc#1/EndorsementInfo: {Version: "1.3", EndorsementPlugin: "builtin", InitRequired: true}
// namespaces/fields/mycc#1/ValidationInfo: {ValidationPlugin: "builtin", ValidationParameter: <application-policy>}
// namespaces/fields/mycc#1/Collections {<collection info>}
// namespaces/metadata/mycc#2: "ChaincodeParameters"
// namespaces/fields/mycc#2/EndorsementInfo: {Version: "1.4", EndorsementPlugin: "builtin", InitRequired: true}
// namespaces/fields/mycc#2/ValidationInfo: {ValidationPlugin: "builtin", ValidationParameter: <application-policy>}
// namespaces/fields/mycc#2/Collections {<collection info>}
//
// chaincode-sources/metadata/mycc#1 "ChaincodeLocalPackage"
// chaincode-sources/fields/mycc#1/PackageID "hash1"
// ChaincodeLocalPackage is a type of chaincode-sources which may be serialized
// into the org's private data collection.
// WARNING: This structure is serialized/deserialized from the DB, re-ordering
// or adding fields will cause opaque checks to fail.
type ChaincodeLocalPackage struct {
PackageID string
}
// ChaincodeParameters are the parts of the chaincode definition which are serialized
// as values in the statedb. It is expected that any instance will have no nil fields once initialized.
// WARNING: This structure is serialized/deserialized from the DB, re-ordering or adding fields
// will cause opaque checks to fail.
type ChaincodeParameters struct {
EndorsementInfo *lb.ChaincodeEndorsementInfo
ValidationInfo *lb.ChaincodeValidationInfo
Collections *pb.CollectionConfigPackage
}
func (cp *ChaincodeParameters) Equal(ocp *ChaincodeParameters) error {
switch {
case cp.EndorsementInfo.Version != ocp.EndorsementInfo.Version:
return errors.Errorf("Version '%s' != '%s'", cp.EndorsementInfo.Version, ocp.EndorsementInfo.Version)
case cp.EndorsementInfo.EndorsementPlugin != ocp.EndorsementInfo.EndorsementPlugin:
return errors.Errorf("EndorsementPlugin '%s' != '%s'", cp.EndorsementInfo.EndorsementPlugin, ocp.EndorsementInfo.EndorsementPlugin)
case cp.EndorsementInfo.InitRequired != ocp.EndorsementInfo.InitRequired:
return errors.Errorf("InitRequired '%t' != '%t'", cp.EndorsementInfo.InitRequired, ocp.EndorsementInfo.InitRequired)
case cp.ValidationInfo.ValidationPlugin != ocp.ValidationInfo.ValidationPlugin:
return errors.Errorf("ValidationPlugin '%s' != '%s'", cp.ValidationInfo.ValidationPlugin, ocp.ValidationInfo.ValidationPlugin)
case !bytes.Equal(cp.ValidationInfo.ValidationParameter, ocp.ValidationInfo.ValidationParameter):
return errors.Errorf("ValidationParameter '%x' != '%x'", cp.ValidationInfo.ValidationParameter, ocp.ValidationInfo.ValidationParameter)
case !proto.Equal(cp.Collections, ocp.Collections):
return errors.Errorf("Collections do not match")
default:
}
return nil
}
// ChaincodeDefinition contains the chaincode parameters, as well as the sequence number of the definition.
// Note, it does not embed ChaincodeParameters so as not to complicate the serialization. It is expected
// that any instance will have no nil fields once initialized.
// WARNING: This structure is serialized/deserialized from the DB, re-ordering or adding fields
// will cause opaque checks to fail.
type ChaincodeDefinition struct {
Sequence int64
EndorsementInfo *lb.ChaincodeEndorsementInfo
ValidationInfo *lb.ChaincodeValidationInfo
Collections *pb.CollectionConfigPackage
}
// Parameters returns the non-sequence info of the chaincode definition
func (cd *ChaincodeDefinition) Parameters() *ChaincodeParameters {
return &ChaincodeParameters{
EndorsementInfo: cd.EndorsementInfo,
ValidationInfo: cd.ValidationInfo,
Collections: cd.Collections,
}
}
func (cd *ChaincodeDefinition) String() string {
endorsementInfo := "endorsement info: <EMPTY>"
if cd.EndorsementInfo != nil {
endorsementInfo = fmt.Sprintf("endorsement info: (version: '%s', plugin: '%s', init required: %t)",
cd.EndorsementInfo.Version,
cd.EndorsementInfo.EndorsementPlugin,
cd.EndorsementInfo.InitRequired,
)
}
validationInfo := "validation info: <EMPTY>"
if cd.ValidationInfo != nil {
validationInfo = fmt.Sprintf("validation info: (plugin: '%s', policy: '%x')",
cd.ValidationInfo.ValidationPlugin,
cd.ValidationInfo.ValidationParameter,
)
}
return fmt.Sprintf("sequence: %d, %s, %s, collections: (%+v)",
cd.Sequence,
endorsementInfo,
validationInfo,
cd.Collections,
)
}
//go:generate counterfeiter -o mock/chaincode_builder.go --fake-name ChaincodeBuilder . ChaincodeBuilder
type ChaincodeBuilder interface {
Build(ccid string) error
}
// ChaincodeStore provides a way to persist chaincodes
type ChaincodeStore interface {
Save(label string, ccInstallPkg []byte) (string, error)
ListInstalledChaincodes() ([]chaincode.InstalledChaincode, error)
Load(packageID string) (ccInstallPkg []byte, err error)
Delete(packageID string) error
}
type PackageParser interface {
Parse(data []byte) (*persistence.ChaincodePackage, error)
}
//go:generate counterfeiter -o mock/install_listener.go --fake-name InstallListener . InstallListener
type InstallListener interface {
HandleChaincodeInstalled(md *persistence.ChaincodePackageMetadata, packageID string)
}
//go:generate counterfeiter -o mock/installed_chaincodes_lister.go --fake-name InstalledChaincodesLister . InstalledChaincodesLister
type InstalledChaincodesLister interface {
ListInstalledChaincodes() []*chaincode.InstalledChaincode
GetInstalledChaincode(packageID string) (*chaincode.InstalledChaincode, error)
}
// Resources stores the common functions needed by all components of the lifecycle
// by the SCC as well as internally. It also has some utility methods attached to it
// for querying the lifecycle definitions.
type Resources struct {
ChannelConfigSource ChannelConfigSource
ChaincodeStore ChaincodeStore
PackageParser PackageParser
Serializer *Serializer
}
// ChaincodeDefinitionIfDefined returns whether the chaincode name is defined in the new lifecycle, a shim around
// the SimpleQueryExecutor to work with the serializer, or an error. If the namespace is defined, but it is
// not a chaincode, this is considered an error.
func (r *Resources) ChaincodeDefinitionIfDefined(chaincodeName string, state ReadableState) (bool, *ChaincodeDefinition, error) {
if chaincodeName == LifecycleNamespace {
return true, &ChaincodeDefinition{
EndorsementInfo: &lb.ChaincodeEndorsementInfo{
InitRequired: false,
},
ValidationInfo: &lb.ChaincodeValidationInfo{},
}, nil
}
metadata, ok, err := r.Serializer.DeserializeMetadata(NamespacesName, chaincodeName, state)
if err != nil {
return false, nil, errors.WithMessagef(err, "could not deserialize metadata for chaincode %s", chaincodeName)
}
if !ok {
return false, nil, nil
}
if metadata.Datatype != ChaincodeDefinitionType {
return false, nil, errors.Errorf("not a chaincode type: %s", metadata.Datatype)
}
definedChaincode := &ChaincodeDefinition{}
err = r.Serializer.Deserialize(NamespacesName, chaincodeName, metadata, definedChaincode, state)
if err != nil {
return false, nil, errors.WithMessagef(err, "could not deserialize chaincode definition for chaincode %s", chaincodeName)
}
return true, definedChaincode, nil
}
func (r *Resources) LifecycleEndorsementPolicyAsBytes(channelID string) ([]byte, error) {
channelConfig := r.ChannelConfigSource.GetStableChannelConfig(channelID)
if channelConfig == nil {
return nil, errors.Errorf("could not get channel config for channel '%s'", channelID)
}
if _, ok := channelConfig.PolicyManager().GetPolicy(LifecycleEndorsementPolicyRef); ok {
return LifecycleDefaultEndorsementPolicyBytes, nil
}
// This was a channel which was upgraded or did not define a lifecycle endorsement policy, use a default
// of "a majority of orgs must have a member sign".
ac, ok := channelConfig.ApplicationConfig()
if !ok {
return nil, errors.Errorf("could not get application config for channel '%s'", channelID)
}
orgs := ac.Organizations()
mspids := make([]string, 0, len(orgs))
for _, org := range orgs {
mspids = append(mspids, org.MSPID())
}
return protoutil.MarshalOrPanic(&cb.ApplicationPolicy{
Type: &cb.ApplicationPolicy_SignaturePolicy{
SignaturePolicy: policydsl.SignedByNOutOfGivenRole(int32(len(mspids)/2+1), msp.MSPRole_MEMBER, mspids),
},
}), nil
}
// ExternalFunctions is intended primarily to support the SCC functions.
// In general, its methods signatures produce writes (which must be commmitted
// as part of an endorsement flow), or return human readable errors (for
// instance indicating a chaincode is not found) rather than sentinels.
// Instead, use the utility functions attached to the lifecycle Resources
// when needed.
type ExternalFunctions struct {
Resources *Resources
InstallListener InstallListener
InstalledChaincodesLister InstalledChaincodesLister
ChaincodeBuilder ChaincodeBuilder
BuildRegistry *container.BuildRegistry
mutex sync.Mutex
BuildLocks map[string]sync.Mutex
}
// CheckCommitReadiness takes a chaincode definition, checks that
// its sequence number is the next allowable sequence number and checks which
// organizations have approved the definition.
func (ef *ExternalFunctions) CheckCommitReadiness(chname, ccname string, cd *ChaincodeDefinition, publicState ReadWritableState, orgStates []OpaqueState) (map[string]bool, error) {
currentSequence, err := ef.Resources.Serializer.DeserializeFieldAsInt64(NamespacesName, ccname, "Sequence", publicState)
if err != nil {
return nil, errors.WithMessage(err, "could not get current sequence")
}
if cd.Sequence != currentSequence+1 {
return nil, errors.Errorf("requested sequence is %d, but new definition must be sequence %d", cd.Sequence, currentSequence+1)
}
if err := ef.SetChaincodeDefinitionDefaults(chname, cd); err != nil {
return nil, errors.WithMessagef(err, "could not set defaults for chaincode definition in channel %s", chname)
}
var approvals map[string]bool
if approvals, err = ef.QueryOrgApprovals(ccname, cd, orgStates); err != nil {
return nil, err
}
logger.Infof("Successfully checked commit readiness of chaincode name '%s' on channel '%s' with definition {%s}", ccname, chname, cd)
return approvals, nil
}
// CommitChaincodeDefinition takes a chaincode definition, checks that its
// sequence number is the next allowable sequence number, checks which
// organizations have approved the definition, and applies the definition to
// the public world state. It is the responsibility of the caller to check
// the approvals to determine if the result is valid (typically, this means
// checking that the peer's own org has approved the definition).
func (ef *ExternalFunctions) CommitChaincodeDefinition(chname, ccname string, cd *ChaincodeDefinition, publicState ReadWritableState, orgStates []OpaqueState) (map[string]bool, error) {
approvals, err := ef.CheckCommitReadiness(chname, ccname, cd, publicState, orgStates)
if err != nil {
return nil, err
}
if err = ef.Resources.Serializer.Serialize(NamespacesName, ccname, cd, publicState); err != nil {
return nil, errors.WithMessage(err, "could not serialize chaincode definition")
}
return approvals, nil
}
// DefaultEndorsementPolicyAsBytes returns a marshalled version
// of the default chaincode endorsement policy in the supplied channel
func (ef *ExternalFunctions) DefaultEndorsementPolicyAsBytes(channelID string) ([]byte, error) {
channelConfig := ef.Resources.ChannelConfigSource.GetStableChannelConfig(channelID)
if channelConfig == nil {
return nil, errors.Errorf("could not get channel config for channel '%s'", channelID)
}
// see if the channel defines a default
if _, ok := channelConfig.PolicyManager().GetPolicy(DefaultEndorsementPolicyRef); ok {
return DefaultEndorsementPolicyBytes, nil
}
return nil, errors.Errorf(
"policy '%s' must be defined for channel '%s' before chaincode operations can be attempted",
DefaultEndorsementPolicyRef,
channelID,
)
}
// SetChaincodeDefinitionDefaults fills any empty fields in the
// supplied ChaincodeDefinition with the supplied channel's defaults
func (ef *ExternalFunctions) SetChaincodeDefinitionDefaults(chname string, cd *ChaincodeDefinition) error {
if cd.EndorsementInfo.EndorsementPlugin == "" {
// TODO:
// 1) rename to "default" or "builtin"
// 2) retrieve from channel config
cd.EndorsementInfo.EndorsementPlugin = "escc"
}
if cd.ValidationInfo.ValidationPlugin == "" {
// TODO:
// 1) rename to "default" or "builtin"
// 2) retrieve from channel config
cd.ValidationInfo.ValidationPlugin = "vscc"
}
if len(cd.ValidationInfo.ValidationParameter) == 0 {
policyBytes, err := ef.DefaultEndorsementPolicyAsBytes(chname)
if err != nil {
return err
}
cd.ValidationInfo.ValidationParameter = policyBytes
}
return nil
}
// ApproveChaincodeDefinitionForOrg adds a chaincode definition entry into the passed in Org state. The definition must be
// for either the currently defined sequence number or the next sequence number. If the definition is
// for the current sequence number, then it must match exactly the current definition or it will be rejected.
func (ef *ExternalFunctions) ApproveChaincodeDefinitionForOrg(chname, ccname string, cd *ChaincodeDefinition, packageID string, publicState ReadableState, orgState ReadWritableState) error {
// Get the current sequence from the public state
currentSequence, err := ef.Resources.Serializer.DeserializeFieldAsInt64(NamespacesName, ccname, "Sequence", publicState)
if err != nil {
return errors.WithMessage(err, "could not get current sequence")
}
requestedSequence := cd.Sequence
if currentSequence == requestedSequence && requestedSequence == 0 {
return errors.Errorf("requested sequence is 0, but first definable sequence number is 1")
}
if requestedSequence < currentSequence {
return errors.Errorf("currently defined sequence %d is larger than requested sequence %d", currentSequence, requestedSequence)
}
if requestedSequence > currentSequence+1 {
return errors.Errorf("requested sequence %d is larger than the next available sequence number %d", requestedSequence, currentSequence+1)
}
if err := ef.SetChaincodeDefinitionDefaults(chname, cd); err != nil {
return errors.WithMessagef(err, "could not set defaults for chaincode definition in channel %s", chname)
}
if requestedSequence == currentSequence {
metadata, ok, err := ef.Resources.Serializer.DeserializeMetadata(NamespacesName, ccname, publicState)
if err != nil {
return errors.WithMessage(err, "could not fetch metadata for current definition")
}
if !ok {
return errors.Errorf("missing metadata for currently committed sequence number (%d)", currentSequence)
}
definedChaincode := &ChaincodeDefinition{}
if err := ef.Resources.Serializer.Deserialize(NamespacesName, ccname, metadata, definedChaincode, publicState); err != nil {
return errors.WithMessagef(err, "could not deserialize namespace %s as chaincode", ccname)
}
if err := definedChaincode.Parameters().Equal(cd.Parameters()); err != nil {
return errors.WithMessagef(err, "attempted to define the current sequence (%d) for namespace %s, but", currentSequence, ccname)
}
}
privateName := fmt.Sprintf("%s#%d", ccname, requestedSequence)
// if requested sequence is not committed, and attempt is made to update its content,
// we need to check whether new definition actually contains updated content, to avoid
// empty write set.
if requestedSequence == currentSequence+1 {
uncommittedMetadata, ok, err := ef.Resources.Serializer.DeserializeMetadata(NamespacesName, privateName, orgState)
if err != nil {
return errors.WithMessage(err, "could not fetch uncommitted definition")
}
if ok {
logger.Debugf("Attempting to redefine uncommitted definition at sequence %d", requestedSequence)
uncommittedParameters := &ChaincodeParameters{}
if err := ef.Resources.Serializer.Deserialize(NamespacesName, privateName, uncommittedMetadata, uncommittedParameters, orgState); err != nil {
return errors.WithMessagef(err, "could not deserialize namespace %s as chaincode", privateName)
}
if err := uncommittedParameters.Equal(cd.Parameters()); err == nil {
// also check package ID updates
metadata, ok, err := ef.Resources.Serializer.DeserializeMetadata(ChaincodeSourcesName, privateName, orgState)
if err != nil {
return errors.WithMessagef(err, "could not deserialize chaincode-source metadata for %s", privateName)
}
if ok {
ccLocalPackage := &ChaincodeLocalPackage{}
if err := ef.Resources.Serializer.Deserialize(ChaincodeSourcesName, privateName, metadata, ccLocalPackage, orgState); err != nil {
return errors.WithMessagef(err, "could not deserialize chaincode package for %s", privateName)
}
if ccLocalPackage.PackageID == packageID {
return errors.Errorf("attempted to redefine uncommitted sequence (%d) for namespace %s with unchanged content", requestedSequence, ccname)
}
}
}
}
}
if err := ef.Resources.Serializer.Serialize(NamespacesName, privateName, cd.Parameters(), orgState); err != nil {
return errors.WithMessage(err, "could not serialize chaincode parameters to state")
}
// set the package id - whether empty or not. Setting
// an empty package ID means that the chaincode won't
// be invocable. The package might be set empty after
// the definition commits as a way of instructing the
// peers of an org no longer to endorse invocations
// for this chaincode
if err := ef.Resources.Serializer.Serialize(ChaincodeSourcesName, privateName, &ChaincodeLocalPackage{
PackageID: packageID,
}, orgState); err != nil {
return errors.WithMessage(err, "could not serialize chaincode package info to state")
}
logger.Infof("Successfully endorsed chaincode approval with name '%s', package ID '%s', on channel '%s' with definition {%s}", ccname, packageID, chname, cd)
return nil
}
// ErrNamespaceNotDefined is the error returned when a namespace
// is not defined. This indicates that the chaincode definition
// has not been committed.
type ErrNamespaceNotDefined struct {
Namespace string
}
func (e ErrNamespaceNotDefined) Error() string {
return fmt.Sprintf("namespace %s is not defined", e.Namespace)
}
// QueryChaincodeDefinition returns the defined chaincode by the given name (if it is committed, and a chaincode)
// or otherwise returns an error.
func (ef *ExternalFunctions) QueryChaincodeDefinition(name string, publicState ReadableState) (*ChaincodeDefinition, error) {
metadata, ok, err := ef.Resources.Serializer.DeserializeMetadata(NamespacesName, name, publicState)
if err != nil {
return nil, errors.WithMessagef(err, "could not fetch metadata for namespace %s", name)
}
if !ok {
return nil, ErrNamespaceNotDefined{Namespace: name}
}
definedChaincode := &ChaincodeDefinition{}
if err := ef.Resources.Serializer.Deserialize(NamespacesName, name, metadata, definedChaincode, publicState); err != nil {
return nil, errors.WithMessagef(err, "could not deserialize namespace %s as chaincode", name)
}
logger.Infof("Successfully queried chaincode name '%s' with definition {%s},", name, definedChaincode)
return definedChaincode, nil
}
// QueryOrgApprovals returns a map containing the orgs whose orgStates were
// provided and whether or not they have approved a chaincode definition with
// the specified parameters.
func (ef *ExternalFunctions) QueryOrgApprovals(name string, cd *ChaincodeDefinition, orgStates []OpaqueState) (map[string]bool, error) {
approvals := map[string]bool{}
privateName := fmt.Sprintf("%s#%d", name, cd.Sequence)
for _, orgState := range orgStates {
match, err := ef.Resources.Serializer.IsSerialized(NamespacesName, privateName, cd.Parameters(), orgState)
if err != nil {
return nil, errors.WithMessagef(err, "serialization check failed for key %s", privateName)
}
org := OrgFromImplicitCollectionName(orgState.CollectionName())
approvals[org] = match
}
return approvals, nil
}
// InstallChaincode installs a given chaincode to the peer's chaincode store.
// It returns the hash to reference the chaincode by or an error on failure.
func (ef *ExternalFunctions) InstallChaincode(chaincodeInstallPackage []byte) (*chaincode.InstalledChaincode, error) {
// Let's validate that the chaincodeInstallPackage is at least well formed before writing it
pkg, err := ef.Resources.PackageParser.Parse(chaincodeInstallPackage)
if err != nil {
return nil, errors.WithMessage(err, "could not parse as a chaincode install package")
}
if pkg.Metadata == nil {
return nil, errors.New("empty metadata for supplied chaincode")
}
packageID, err := ef.Resources.ChaincodeStore.Save(pkg.Metadata.Label, chaincodeInstallPackage)
if err != nil {
return nil, errors.WithMessage(err, "could not save cc install package")
}
buildLock := ef.getBuildLock(packageID)
buildLock.Lock()
defer buildLock.Unlock()
buildStatus, ok := ef.BuildRegistry.BuildStatus(packageID)
if ok {
// another invocation of lifecycle has concurrently
// installed a chaincode with this package id
<-buildStatus.Done()
if buildStatus.Err() == nil {
return nil, errors.New("chaincode already successfully installed")
}
buildStatus = ef.BuildRegistry.ResetBuildStatus(packageID)
}
err = ef.ChaincodeBuilder.Build(packageID)
buildStatus.Notify(err)
<-buildStatus.Done()
if err := buildStatus.Err(); err != nil {
ef.Resources.ChaincodeStore.Delete(packageID)
return nil, errors.WithMessage(err, "could not build chaincode")
}
if ef.InstallListener != nil {
ef.InstallListener.HandleChaincodeInstalled(pkg.Metadata, packageID)
}
logger.Infof("Successfully installed chaincode with package ID '%s'", packageID)
return &chaincode.InstalledChaincode{
PackageID: packageID,
Label: pkg.Metadata.Label,
}, nil
}
func (ef *ExternalFunctions) getBuildLock(packageID string) *sync.Mutex {
ef.mutex.Lock()
defer ef.mutex.Unlock()
if ef.BuildLocks == nil {
ef.BuildLocks = map[string]sync.Mutex{}
}
buildLock, ok := ef.BuildLocks[packageID]
if !ok {
ef.BuildLocks[packageID] = sync.Mutex{}
}
return &buildLock
}
// GetInstalledChaincodePackage retrieves the installed chaincode with the given package ID
// from the peer's chaincode store.
func (ef *ExternalFunctions) GetInstalledChaincodePackage(packageID string) ([]byte, error) {
pkgBytes, err := ef.Resources.ChaincodeStore.Load(packageID)
if err != nil {
return nil, errors.WithMessage(err, "could not load cc install package")
}
return pkgBytes, nil
}
// QueryNamespaceDefinitions lists the publicly defined namespaces in a channel. Today it should only ever
// find Datatype encodings of 'ChaincodeDefinition'.
func (ef *ExternalFunctions) QueryNamespaceDefinitions(publicState RangeableState) (map[string]string, error) {
metadatas, err := ef.Resources.Serializer.DeserializeAllMetadata(NamespacesName, publicState)
if err != nil {
return nil, errors.WithMessage(err, "could not query namespace metadata")
}
result := map[string]string{}
for key, value := range metadatas {
switch value.Datatype {
case ChaincodeDefinitionType:
result[key] = FriendlyChaincodeDefinitionType
default:
// This should never execute, but seems preferable to returning an error
result[key] = value.Datatype
}
}
return result, nil
}
// QueryInstalledChaincode returns metadata for the chaincode with the supplied package ID.
func (ef *ExternalFunctions) QueryInstalledChaincode(packageID string) (*chaincode.InstalledChaincode, error) {
return ef.InstalledChaincodesLister.GetInstalledChaincode(packageID)
}
// QueryInstalledChaincodes returns a list of installed chaincodes
func (ef *ExternalFunctions) QueryInstalledChaincodes() []*chaincode.InstalledChaincode {
return ef.InstalledChaincodesLister.ListInstalledChaincodes()
}
Go
1
https://gitee.com/mirrors/hyperledger-fabric.git
git@gitee.com:mirrors/hyperledger-fabric.git
mirrors
hyperledger-fabric
hyperledger-fabric
v2.1.1

搜索帮助