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