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 }