github.com/hechain20/hechain@v0.0.0-20220316014945-b544036ba106/core/chaincode/lifecycle/metadata_provider.go (about)

     1  /*
     2  Copyright hechain. All Rights Reserved.
     3  
     4  SPDX-License-Identifier: Apache-2.0
     5  */
     6  
     7  package lifecycle
     8  
     9  import (
    10  	"strconv"
    11  
    12  	"github.com/golang/protobuf/proto"
    13  	"github.com/hechain20/hechain/common/chaincode"
    14  	"github.com/hechain20/hechain/common/policies"
    15  	"github.com/hechain20/hechain/common/policydsl"
    16  	"github.com/hechain20/hechain/core/chaincode/implicitcollection"
    17  	"github.com/hechain20/hechain/protoutil"
    18  	"github.com/hyperledger/fabric-protos-go/peer"
    19  	"github.com/pkg/errors"
    20  )
    21  
    22  // LegacyMetadataProvider provides metadata for a lscc-defined chaincode
    23  // on a specific channel.
    24  type LegacyMetadataProvider interface {
    25  	Metadata(channel string, cc string, collections ...string) *chaincode.Metadata
    26  }
    27  
    28  // ChaincodeInfoProvider provides metadata for a _lifecycle-defined
    29  // chaincode on a specific channel
    30  type ChaincodeInfoProvider interface {
    31  	// ChaincodeInfo returns the chaincode definition and its install info.
    32  	// An error is returned only if either the channel or the chaincode do not exist.
    33  	ChaincodeInfo(channelID, name string) (*LocalChaincodeInfo, error)
    34  }
    35  
    36  // ChannelPolicyReferenceProvider is used to determine if a set of signature is valid and complies with a policy
    37  type ChannelPolicyReferenceProvider interface {
    38  	// NewPolicy creates a new policy based on the policy bytes
    39  	NewPolicy(channelID, channelConfigPolicyReference string) (policies.Policy, error)
    40  }
    41  
    42  type channelPolicyReferenceProviderImpl struct {
    43  	ChannelConfigSource
    44  }
    45  
    46  // NewPolicy implements the method of the same name of the ChannelPolicyReferenceProvider interface
    47  func (c *channelPolicyReferenceProviderImpl) NewPolicy(channelID, channelConfigPolicyReference string) (policies.Policy, error) {
    48  	cc := c.GetStableChannelConfig(channelID)
    49  	pm := cc.PolicyManager()
    50  	p, ok := pm.GetPolicy(channelConfigPolicyReference)
    51  	if !ok {
    52  		return nil, errors.Errorf("could not retrieve policy for reference '%s' on channel '%s'", channelConfigPolicyReference, channelID)
    53  	}
    54  
    55  	return p, nil
    56  }
    57  
    58  // NewMetadataProvider returns a new MetadataProvider instance
    59  func NewMetadataProvider(cip ChaincodeInfoProvider, lmp LegacyMetadataProvider, ccs ChannelConfigSource) *MetadataProvider {
    60  	return &MetadataProvider{
    61  		ChaincodeInfoProvider:  cip,
    62  		LegacyMetadataProvider: lmp,
    63  		ChannelPolicyReferenceProvider: &channelPolicyReferenceProviderImpl{
    64  			ChannelConfigSource: ccs,
    65  		},
    66  	}
    67  }
    68  
    69  type MetadataProvider struct {
    70  	ChaincodeInfoProvider          ChaincodeInfoProvider
    71  	LegacyMetadataProvider         LegacyMetadataProvider
    72  	ChannelPolicyReferenceProvider ChannelPolicyReferenceProvider
    73  }
    74  
    75  func (mp *MetadataProvider) toSignaturePolicyEnvelope(channelID string, policyBytes []byte) ([]byte, error) {
    76  	p := &peer.ApplicationPolicy{}
    77  	err := proto.Unmarshal(policyBytes, p)
    78  	if err != nil {
    79  		return nil, errors.Wrap(err, "failed to unmarshal ApplicationPolicy bytes")
    80  	}
    81  
    82  	switch policy := p.Type.(type) {
    83  	case *peer.ApplicationPolicy_SignaturePolicy:
    84  		return protoutil.MarshalOrPanic(policy.SignaturePolicy), nil
    85  	case *peer.ApplicationPolicy_ChannelConfigPolicyReference:
    86  		p, err := mp.ChannelPolicyReferenceProvider.NewPolicy(channelID, policy.ChannelConfigPolicyReference)
    87  		if err != nil {
    88  			return nil, errors.WithMessagef(err, "could not retrieve policy for reference '%s' on channel '%s'", policy.ChannelConfigPolicyReference, channelID)
    89  		}
    90  
    91  		cp, ok := p.(policies.Converter)
    92  		if !ok {
    93  			return nil, errors.Errorf("policy with reference '%s' on channel '%s' is not convertible to SignaturePolicyEnvelope", policy.ChannelConfigPolicyReference, channelID)
    94  		}
    95  
    96  		spe, err := cp.Convert()
    97  		if err != nil {
    98  			return nil, errors.WithMessagef(err, "error converting policy with reference '%s' on channel '%s' to SignaturePolicyEnvelope", policy.ChannelConfigPolicyReference, channelID)
    99  		}
   100  
   101  		return proto.Marshal(spe)
   102  	default:
   103  		// this will only happen if a new policy type is added to the oneof
   104  		return nil, errors.Errorf("unsupported policy type %T on channel '%s'", policy, channelID)
   105  	}
   106  }
   107  
   108  // Metadata implements the metadata retriever support interface for service discovery
   109  func (mp *MetadataProvider) Metadata(channel string, ccName string, collections ...string) *chaincode.Metadata {
   110  	ccInfo, err := mp.ChaincodeInfoProvider.ChaincodeInfo(channel, ccName)
   111  	if err != nil {
   112  		logger.Debugf("chaincode '%s' on channel '%s' not defined in _lifecycle. requesting metadata from lscc", ccName, channel)
   113  		// fallback to legacy metadata via cclifecycle
   114  		return mp.LegacyMetadataProvider.Metadata(channel, ccName, collections...)
   115  	}
   116  
   117  	spe, err := mp.toSignaturePolicyEnvelope(channel, ccInfo.Definition.ValidationInfo.ValidationParameter)
   118  	if err != nil {
   119  		logger.Errorf("could not convert policy for chaincode '%s' on channel '%s', err '%s'", ccName, channel, err)
   120  		return nil
   121  	}
   122  
   123  	// report the sequence as the version to service discovery since
   124  	// the version is no longer required to change when updating any
   125  	// part of the chaincode definition
   126  	ccMetadata := &chaincode.Metadata{
   127  		Name:               ccName,
   128  		Version:            strconv.FormatInt(ccInfo.Definition.Sequence, 10),
   129  		Policy:             spe,
   130  		CollectionPolicies: map[string][]byte{},
   131  		CollectionsConfig:  ccInfo.Definition.Collections,
   132  	}
   133  
   134  	for _, col := range collections {
   135  		if isImplicit, mspID := implicitcollection.MspIDIfImplicitCollection(col); isImplicit {
   136  			// Implicit collection
   137  
   138  			// Initialize definition of collections if it's missing
   139  			if ccInfo.Definition.Collections == nil {
   140  				ccInfo.Definition.Collections = &peer.CollectionConfigPackage{}
   141  			}
   142  
   143  			spe := policydsl.SignedByMspMember(mspID)
   144  			ccInfo.Definition.Collections.Config = append(ccInfo.Definition.Collections.Config, &peer.CollectionConfig{
   145  				Payload: &peer.CollectionConfig_StaticCollectionConfig{
   146  					StaticCollectionConfig: &peer.StaticCollectionConfig{
   147  						Name: col,
   148  						MemberOrgsPolicy: &peer.CollectionPolicyConfig{
   149  							Payload: &peer.CollectionPolicyConfig_SignaturePolicy{
   150  								SignaturePolicy: spe,
   151  							},
   152  						},
   153  						EndorsementPolicy: &peer.ApplicationPolicy{
   154  							Type: &peer.ApplicationPolicy_SignaturePolicy{
   155  								SignaturePolicy: spe,
   156  							},
   157  						},
   158  					},
   159  				},
   160  			})
   161  		}
   162  	}
   163  
   164  	if ccInfo.Definition.Collections == nil {
   165  		return ccMetadata
   166  	}
   167  
   168  	// process any existing collection endorsement policies
   169  	for _, collectionName := range collections {
   170  		for _, conf := range ccInfo.Definition.Collections.Config {
   171  			staticCollConfig := conf.GetStaticCollectionConfig()
   172  			if staticCollConfig == nil {
   173  				continue
   174  			}
   175  			if staticCollConfig.Name == collectionName {
   176  				if staticCollConfig.EndorsementPolicy != nil {
   177  					ep := protoutil.MarshalOrPanic(staticCollConfig.EndorsementPolicy)
   178  					cspe, err := mp.toSignaturePolicyEnvelope(channel, ep)
   179  					if err != nil {
   180  						logger.Errorf("could not convert collection policy for chaincode '%s' collection '%s' on channel '%s', err '%s'", ccName, collectionName, channel, err)
   181  						return nil
   182  					}
   183  					ccMetadata.CollectionPolicies[collectionName] = cspe
   184  				}
   185  			}
   186  		}
   187  	}
   188  
   189  	return ccMetadata
   190  }