github.com/ewagmig/fabric@v2.1.1+incompatible/core/chaincode/lifecycle/metadata_provider.go (about)

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