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 }