1 Star 0 Fork 0

peter / fabric

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
克隆/下载
deployedcc_infoprovider.go 13.58 KB
一键复制 编辑 原始数据 按行查看 历史
/*
Copyright IBM Corp. All Rights Reserved.
SPDX-License-Identifier: Apache-2.0
*/
package lifecycle
import (
"fmt"
"regexp"
"strings"
cb "github.com/hyperledger/fabric-protos-go/common"
"github.com/hyperledger/fabric-protos-go/ledger/rwset/kvrwset"
pb "github.com/hyperledger/fabric-protos-go/peer"
"github.com/hyperledger/fabric/common/policydsl"
"github.com/hyperledger/fabric/common/util"
validationState "github.com/hyperledger/fabric/core/handlers/validation/api/state"
"github.com/hyperledger/fabric/core/ledger"
"github.com/hyperledger/fabric/core/peer"
"github.com/hyperledger/fabric/gossip/privdata"
"github.com/hyperledger/fabric/protoutil"
"github.com/pkg/errors"
)
//go:generate counterfeiter -o mock/legacy_ccinfo.go --fake-name LegacyDeployedCCInfoProvider . LegacyDeployedCCInfoProvider
type LegacyDeployedCCInfoProvider interface {
ledger.DeployedChaincodeInfoProvider
}
const (
LifecycleEndorsementPolicyRef = "/Channel/Application/LifecycleEndorsement"
)
var (
// This is a channel which was created with a lifecycle endorsement policy
LifecycleDefaultEndorsementPolicyBytes = protoutil.MarshalOrPanic(&cb.ApplicationPolicy{
Type: &cb.ApplicationPolicy_ChannelConfigPolicyReference{
ChannelConfigPolicyReference: LifecycleEndorsementPolicyRef,
},
})
)
type ValidatorCommitter struct {
CoreConfig *peer.Config
PrivdataConfig *privdata.PrivdataConfig
Resources *Resources
LegacyDeployedCCInfoProvider LegacyDeployedCCInfoProvider
}
// Namespaces returns the list of namespaces which are relevant to chaincode lifecycle
func (vc *ValidatorCommitter) Namespaces() []string {
return append([]string{LifecycleNamespace}, vc.LegacyDeployedCCInfoProvider.Namespaces()...)
}
var SequenceMatcher = regexp.MustCompile("^" + NamespacesName + "/fields/([^/]+)/Sequence$")
// UpdatedChaincodes returns the chaincodes that are getting updated by the supplied 'stateUpdates'
func (vc *ValidatorCommitter) UpdatedChaincodes(stateUpdates map[string][]*kvrwset.KVWrite) ([]*ledger.ChaincodeLifecycleInfo, error) {
lifecycleInfo := []*ledger.ChaincodeLifecycleInfo{}
// If the lifecycle table was updated, report only modified chaincodes
lifecycleUpdates := stateUpdates[LifecycleNamespace]
for _, kvWrite := range lifecycleUpdates {
matches := SequenceMatcher.FindStringSubmatch(kvWrite.Key)
if len(matches) != 2 {
continue
}
// XXX Note, this may not be a chaincode namespace, handle this later
lifecycleInfo = append(lifecycleInfo, &ledger.ChaincodeLifecycleInfo{Name: matches[1]})
}
legacyUpdates, err := vc.LegacyDeployedCCInfoProvider.UpdatedChaincodes(stateUpdates)
if err != nil {
return nil, errors.WithMessage(err, "error invoking legacy deployed cc info provider")
}
return append(lifecycleInfo, legacyUpdates...), nil
}
func (vc *ValidatorCommitter) ChaincodeInfo(channelName, chaincodeName string, qe ledger.SimpleQueryExecutor) (*ledger.DeployedChaincodeInfo, error) {
exists, definedChaincode, err := vc.Resources.ChaincodeDefinitionIfDefined(chaincodeName, &SimpleQueryExecutorShim{
Namespace: LifecycleNamespace,
SimpleQueryExecutor: qe,
})
if err != nil {
return nil, errors.WithMessage(err, "could not get info about chaincode")
}
if !exists {
return vc.LegacyDeployedCCInfoProvider.ChaincodeInfo(channelName, chaincodeName, qe)
}
return &ledger.DeployedChaincodeInfo{
Name: chaincodeName,
Version: definedChaincode.EndorsementInfo.Version,
Hash: util.ComputeSHA256([]byte(chaincodeName + ":" + definedChaincode.EndorsementInfo.Version)),
ExplicitCollectionConfigPkg: definedChaincode.Collections,
IsLegacy: false,
}, nil
}
var ImplicitCollectionMatcher = regexp.MustCompile("^" + ImplicitCollectionNameForOrg("(.+)") + "$")
// AllCollectionsConfigPkg implements function in interface ledger.DeployedChaincodeInfoProvider
// this implementation returns a combined collection config pkg that contains both explicit and implicit collections
func (vc *ValidatorCommitter) AllCollectionsConfigPkg(channelName, chaincodeName string, qe ledger.SimpleQueryExecutor) (*pb.CollectionConfigPackage, error) {
chaincodeInfo, err := vc.ChaincodeInfo(channelName, chaincodeName, qe)
if err != nil {
return nil, err
}
explicitCollectionConfigPkg := chaincodeInfo.ExplicitCollectionConfigPkg
if chaincodeInfo.IsLegacy {
return explicitCollectionConfigPkg, nil
}
implicitCollections, err := vc.ImplicitCollections(channelName, chaincodeName, qe)
if err != nil {
return nil, err
}
var combinedColls []*pb.CollectionConfig
if explicitCollectionConfigPkg != nil {
combinedColls = append(combinedColls, explicitCollectionConfigPkg.Config...)
}
for _, implicitColl := range implicitCollections {
c := &pb.CollectionConfig{}
c.Payload = &pb.CollectionConfig_StaticCollectionConfig{StaticCollectionConfig: implicitColl}
combinedColls = append(combinedColls, c)
}
return &pb.CollectionConfigPackage{
Config: combinedColls,
}, nil
}
// CollectionInfo implements function in interface ledger.DeployedChaincodeInfoProvider, it returns config for
// both static and implicit collections.
func (vc *ValidatorCommitter) CollectionInfo(channelName, chaincodeName, collectionName string, qe ledger.SimpleQueryExecutor) (*pb.StaticCollectionConfig, error) {
exists, definedChaincode, err := vc.Resources.ChaincodeDefinitionIfDefined(chaincodeName, &SimpleQueryExecutorShim{
Namespace: LifecycleNamespace,
SimpleQueryExecutor: qe,
})
if err != nil {
return nil, errors.WithMessage(err, "could not get chaincode")
}
if !exists {
return vc.LegacyDeployedCCInfoProvider.CollectionInfo(channelName, chaincodeName, collectionName, qe)
}
matches := ImplicitCollectionMatcher.FindStringSubmatch(collectionName)
if len(matches) == 2 {
return vc.GenerateImplicitCollectionForOrg(matches[1]), nil
}
if definedChaincode.Collections != nil {
for _, conf := range definedChaincode.Collections.Config {
staticCollConfig := conf.GetStaticCollectionConfig()
if staticCollConfig != nil && staticCollConfig.Name == collectionName {
return staticCollConfig, nil
}
}
}
return nil, nil
}
// ImplicitCollections implements function in interface ledger.DeployedChaincodeInfoProvider. It returns
//a slice that contains one proto msg for each of the implicit collections
func (vc *ValidatorCommitter) ImplicitCollections(channelName, chaincodeName string, qe ledger.SimpleQueryExecutor) ([]*pb.StaticCollectionConfig, error) {
exists, _, err := vc.Resources.ChaincodeDefinitionIfDefined(chaincodeName, &SimpleQueryExecutorShim{
Namespace: LifecycleNamespace,
SimpleQueryExecutor: qe,
})
if err != nil {
return nil, errors.WithMessage(err, "could not get info about chaincode")
}
if !exists {
// Implicit collections are a v2.0 lifecycle concept, if the chaincode is not in the new lifecycle, return nothing
return nil, nil
}
return vc.ChaincodeImplicitCollections(channelName)
}
// ChaincodeImplicitCollections assumes the chaincode exists in the new lifecycle and returns the implicit collections
func (vc *ValidatorCommitter) ChaincodeImplicitCollections(channelName string) ([]*pb.StaticCollectionConfig, error) {
channelConfig := vc.Resources.ChannelConfigSource.GetStableChannelConfig(channelName)
if channelConfig == nil {
return nil, errors.Errorf("could not get channelconfig for channel %s", channelName)
}
ac, ok := channelConfig.ApplicationConfig()
if !ok {
return nil, errors.Errorf("could not get application config for channel %s", channelName)
}
orgs := ac.Organizations()
implicitCollections := make([]*pb.StaticCollectionConfig, 0, len(orgs))
for _, org := range orgs {
implicitCollections = append(implicitCollections, vc.GenerateImplicitCollectionForOrg(org.MSPID()))
}
return implicitCollections, nil
}
// GenerateImplicitCollectionForOrg generates implicit collection for the org
func (vc *ValidatorCommitter) GenerateImplicitCollectionForOrg(mspid string) *pb.StaticCollectionConfig {
// set Required/MaxPeerCount to 0 if it is other org's implicit collection (mspid does not match peer's local mspid)
// set Required/MaxPeerCount to the config values if it is the peer org's implicit collection (mspid matches peer's local mspid)
requiredPeerCount := 0
maxPeerCount := 0
if mspid == vc.CoreConfig.LocalMSPID {
requiredPeerCount = vc.PrivdataConfig.ImplicitCollDisseminationPolicy.RequiredPeerCount
maxPeerCount = vc.PrivdataConfig.ImplicitCollDisseminationPolicy.MaxPeerCount
}
return &pb.StaticCollectionConfig{
Name: ImplicitCollectionNameForOrg(mspid),
MemberOrgsPolicy: &pb.CollectionPolicyConfig{
Payload: &pb.CollectionPolicyConfig_SignaturePolicy{
SignaturePolicy: policydsl.SignedByMspMember(mspid),
},
},
RequiredPeerCount: int32(requiredPeerCount),
MaximumPeerCount: int32(maxPeerCount),
}
}
func ImplicitCollectionNameForOrg(mspid string) string {
return fmt.Sprintf("_implicit_org_%s", mspid)
}
func OrgFromImplicitCollectionName(name string) string {
return strings.TrimPrefix(name, "_implicit_org_")
}
func (vc *ValidatorCommitter) ImplicitCollectionEndorsementPolicyAsBytes(channelID, orgMSPID string) (policy []byte, unexpectedErr, validationErr error) {
channelConfig := vc.Resources.ChannelConfigSource.GetStableChannelConfig(channelID)
if channelConfig == nil {
return nil, errors.Errorf("could not get channel config for channel '%s'", channelID), nil
}
ac, ok := channelConfig.ApplicationConfig()
if !ok {
return nil, errors.Errorf("could not get application config for channel '%s'", channelID), nil
}
matchedOrgName := ""
for orgName, org := range ac.Organizations() {
if org.MSPID() == orgMSPID {
matchedOrgName = orgName
break
}
}
if matchedOrgName == "" {
return nil, nil, errors.Errorf("no org found in channel with MSPID '%s'", orgMSPID)
}
policyName := fmt.Sprintf("/Channel/Application/%s/Endorsement", matchedOrgName)
if _, ok := channelConfig.PolicyManager().GetPolicy(policyName); ok {
return protoutil.MarshalOrPanic(&cb.ApplicationPolicy{
Type: &cb.ApplicationPolicy_ChannelConfigPolicyReference{
ChannelConfigPolicyReference: policyName,
},
}), nil, nil
}
// This was a channel which was upgraded or did not define an org level endorsement policy, use a default
// of "any member of the org"
return protoutil.MarshalOrPanic(&cb.ApplicationPolicy{
Type: &cb.ApplicationPolicy_SignaturePolicy{
SignaturePolicy: policydsl.SignedByAnyMember([]string{orgMSPID}),
},
}), nil, nil
}
// ValidationInfo returns the name and arguments of the validation plugin for the supplied
// chaincode. The function returns two types of errors, unexpected errors and validation
// errors. The reason for this is that this function is called from the validation code,
// which needs to differentiate the two types of error to halt processing on the channel
// if the unexpected error is not nil and mark the transaction as invalid if the validation
// error is not nil.
func (vc *ValidatorCommitter) ValidationInfo(channelID, chaincodeName string, qe ledger.SimpleQueryExecutor) (plugin string, args []byte, unexpectedErr error, validationErr error) {
// TODO, this is a bit of an overkill check, and will need to be scaled back for non-chaincode type namespaces
exists, definedChaincode, err := vc.Resources.ChaincodeDefinitionIfDefined(chaincodeName, &SimpleQueryExecutorShim{
Namespace: LifecycleNamespace,
SimpleQueryExecutor: qe,
})
if err != nil {
return "", nil, errors.WithMessage(err, "could not get chaincode"), nil
}
if !exists {
// TODO, this is inconsistent with how the legacy lifecycle reports
// that a missing chaincode is a validation error. But, for now
// this is required to make the passthrough work.
return "", nil, nil, nil
}
if chaincodeName == LifecycleNamespace {
b, err := vc.Resources.LifecycleEndorsementPolicyAsBytes(channelID)
if err != nil {
return "", nil, errors.WithMessage(err, "unexpected failure to create lifecycle endorsement policy"), nil
}
return "vscc", b, nil, nil
}
return definedChaincode.ValidationInfo.ValidationPlugin, definedChaincode.ValidationInfo.ValidationParameter, nil, nil
}
// CollectionValidationInfo returns information about collections to the validation component
func (vc *ValidatorCommitter) CollectionValidationInfo(channelID, chaincodeName, collectionName string, state validationState.State) (args []byte, unexpectedErr, validationErr error) {
exists, definedChaincode, err := vc.Resources.ChaincodeDefinitionIfDefined(chaincodeName, &ValidatorStateShim{
Namespace: LifecycleNamespace,
ValidatorState: state,
})
if err != nil {
return nil, errors.WithMessage(err, "could not get chaincode"), nil
}
if !exists {
// TODO, this is inconsistent with how the legacy lifecycle reports
// that a missing chaincode is a validation error. But, for now
// this is required to make the passthrough work.
return nil, nil, nil
}
matches := ImplicitCollectionMatcher.FindStringSubmatch(collectionName)
if len(matches) == 2 {
return vc.ImplicitCollectionEndorsementPolicyAsBytes(channelID, matches[1])
}
if definedChaincode.Collections != nil {
for _, conf := range definedChaincode.Collections.Config {
staticCollConfig := conf.GetStaticCollectionConfig()
if staticCollConfig != nil && staticCollConfig.Name == collectionName {
if staticCollConfig.EndorsementPolicy != nil {
return protoutil.MarshalOrPanic(staticCollConfig.EndorsementPolicy), nil, nil
}
// default to chaincode endorsement policy
return definedChaincode.ValidationInfo.ValidationParameter, nil, nil
}
}
}
return nil, nil, errors.Errorf("no such collection '%s'", collectionName)
}
1
https://gitee.com/peter_code_git/fabric.git
git@gitee.com:peter_code_git/fabric.git
peter_code_git
fabric
fabric
v2.1.1

搜索帮助