@@ -79,14 +79,18 @@ type peerPrincipalEvaluator func(member discovery2.NetworkMember, principal *msp
79
79
80
80
// PeersForEndorsement returns an EndorsementDescriptor for a given set of peers, channel, and chaincode
81
81
func (ea * endorsementAnalyzer ) PeersForEndorsement (chainID common.ChainID , interest * discovery.ChaincodeInterest ) (* discovery.EndorsementDescriptor , error ) {
82
- chaincode := interest .Chaincodes [0 ]
83
- loadCollections := len (chaincode .CollectionNames ) > 0
84
- ccMD := ea .Metadata (string (chainID ), chaincode .Name , loadCollections )
85
- if ccMD == nil {
86
- return nil , errors .Errorf ("No metadata was found for chaincode %s in channel %s" , chaincode .Name , string (chainID ))
82
+ // For now we only support a single chaincode
83
+ if len (interest .Chaincodes ) != 1 {
84
+ return nil , errors .New ("only a single chaincode is supported" )
85
+ }
86
+ interest .Chaincodes = []* discovery.ChaincodeCall {interest .Chaincodes [0 ]}
87
+
88
+ metadataAndCollectionFilters , err := loadMetadataAndFilters (chainID , interest , ea )
89
+ if err != nil {
90
+ return nil , errors .WithStack (err )
87
91
}
88
92
// Filter out peers that don't have the chaincode installed on them
89
- chanMembership := ea .PeersOfChannel (chainID ).Filter (peersWithChaincode (ccMD ))
93
+ chanMembership := ea .PeersOfChannel (chainID ).Filter (peersWithChaincode (metadataAndCollectionFilters . md ... ))
90
94
channelMembersById := chanMembership .ByID ()
91
95
// Choose only the alive messages of those that have joined the channel
92
96
aliveMembership := ea .Peers ().Intersect (chanMembership )
@@ -95,68 +99,179 @@ func (ea *endorsementAnalyzer) PeersForEndorsement(chainID common.ChainID, inter
95
99
identities := ea .IdentityInfo ()
96
100
identitiesOfMembers := computeIdentitiesOfMembers (identities , membersById )
97
101
98
- // Retrieve the policy for the chaincode
99
- pol := ea .PolicyByChaincode (string (chainID ), chaincode .Name )
100
- if pol == nil {
101
- logger .Debug ("Policy for chaincode '" , chaincode , "'doesn't exist" )
102
- return nil , errors .New ("policy not found" )
102
+ // Retrieve the policies for the chaincodes
103
+ pols , err := ea .loadPolicies (chainID , interest )
104
+ if err != nil {
105
+ return nil , errors .WithStack (err )
103
106
}
107
+ // For now we take the first policy and ignore the rest
108
+ pol := pols [0 ]
104
109
105
110
// Compute the combinations of principals (principal sets) that satisfy the endorsement policy
106
111
principalsSets := policies .PrincipalSets (pol .SatisfiedBy ())
107
112
108
- // Obtain the MSP IDs of the members of the channel that are alive
109
- mspIDsOfChannelPeers := mspIDsOfMembers (membersById , identities .ByID ())
110
113
// Filter out principal sets that contain MSP IDs for peers that don't have the chaincode(s) installed
111
- principalsSets = principalsSets .ContainingOnly (func (principal * msp.MSPPrincipal ) bool {
112
- mspID := ea .MSPOfPrincipal (principal )
113
- _ , exists := mspIDsOfChannelPeers [mspID ]
114
- return mspID != "" && exists
115
- })
114
+ principalsSets = ea .excludeIfCCNotInstalled (principalsSets , membersById , identities .ByID ())
116
115
117
- if loadCollections {
118
- filterByCollections , err := newCollectionFilter (ccMD .CollectionsConfig )
119
- if err != nil {
120
- return nil , errors .Wrap (err , "failed creating collection filter" )
121
- }
122
- for _ , col := range chaincode .CollectionNames {
123
- principalsSets , err = filterByCollections (col , principalsSets )
124
- if err != nil {
125
- return nil , errors .Wrapf (err , "failed filtering collection %s for chaincode %s" , col , chaincode .Name )
126
- }
127
- }
116
+ // Filter the principal sets by the collections (if applicable)
117
+ principalsSets , err = metadataAndCollectionFilters .filter (principalsSets )
118
+ if err != nil {
119
+ return nil , errors .WithStack (err )
128
120
}
129
121
122
+ return ea .computeEndorsementResponse (& context {
123
+ chaincode : interest .Chaincodes [0 ].Name ,
124
+ channel : string (chainID ),
125
+ principalsSets : principalsSets ,
126
+ channelMembersById : channelMembersById ,
127
+ aliveMembership : aliveMembership ,
128
+ identitiesOfMembers : identitiesOfMembers ,
129
+ })
130
+ }
131
+
132
+ type context struct {
133
+ chaincode string
134
+ channel string
135
+ aliveMembership discovery2.Members
136
+ principalsSets []policies.PrincipalSet
137
+ channelMembersById map [string ]discovery2.NetworkMember
138
+ identitiesOfMembers memberIdentities
139
+ }
140
+
141
+ func (ea * endorsementAnalyzer ) computeEndorsementResponse (ctx * context ) (* discovery.EndorsementDescriptor , error ) {
130
142
// mapPrincipalsToGroups returns a mapping from principals to their corresponding groups.
131
143
// groups are just human readable representations that mask the principals behind them
132
- principalGroups := mapPrincipalsToGroups (principalsSets )
144
+ principalGroups := mapPrincipalsToGroups (ctx . principalsSets )
133
145
// principalsToPeersGraph computes a bipartite graph (V1 U V2 , E)
134
146
// such that V1 is the peers, V2 are the principals,
135
147
// and each e=(peer,principal) is in E if the peer satisfies the principal
136
148
satGraph := principalsToPeersGraph (principalAndPeerData {
137
- members : aliveMembership ,
149
+ members : ctx . aliveMembership ,
138
150
pGrps : principalGroups ,
139
- }, ea .satisfiesPrincipal (string ( chainID ), identitiesOfMembers ))
151
+ }, ea .satisfiesPrincipal (ctx . channel , ctx . identitiesOfMembers ))
140
152
141
- layouts := computeLayouts (principalsSets , principalGroups , satGraph )
153
+ layouts := computeLayouts (ctx . principalsSets , principalGroups , satGraph )
142
154
if len (layouts ) == 0 {
143
155
return nil , errors .New ("cannot satisfy any principal combination" )
144
156
}
145
157
146
158
criteria := & peerMembershipCriteria {
147
159
possibleLayouts : layouts ,
148
160
satGraph : satGraph ,
149
- chanMemberById : channelMembersById ,
150
- idOfMembers : identitiesOfMembers ,
161
+ chanMemberById : ctx . channelMembersById ,
162
+ idOfMembers : ctx . identitiesOfMembers ,
151
163
}
152
164
153
165
return & discovery.EndorsementDescriptor {
154
- Chaincode : chaincode . Name ,
166
+ Chaincode : ctx . chaincode ,
155
167
Layouts : layouts ,
156
168
EndorsersByGroups : endorsersByGroup (criteria ),
157
169
}, nil
158
170
}
159
171
172
+ func (ea * endorsementAnalyzer ) excludeIfCCNotInstalled (principalsSets policies.PrincipalSets , membersById map [string ]discovery2.NetworkMember , identitiesByID map [string ]api.PeerIdentityInfo ) policies.PrincipalSets {
173
+ // Obtain the MSP IDs of the members of the channel that are alive
174
+ mspIDsOfChannelPeers := mspIDsOfMembers (membersById , identitiesByID )
175
+ principalsSets = ea .excludePrincipals (func (principal * msp.MSPPrincipal ) bool {
176
+ mspID := ea .MSPOfPrincipal (principal )
177
+ _ , exists := mspIDsOfChannelPeers [mspID ]
178
+ return mspID != "" && exists
179
+ }, principalsSets )
180
+ return principalsSets
181
+ }
182
+
183
+ func (ea * endorsementAnalyzer ) excludePrincipals (filter func (principal * msp.MSPPrincipal ) bool , sets ... policies.PrincipalSets ) policies.PrincipalSets {
184
+ var res []policies.PrincipalSets
185
+ for _ , principalSets := range sets {
186
+ principalSets = principalSets .ContainingOnly (filter )
187
+ if len (principalSets ) == 0 {
188
+ continue
189
+ }
190
+ res = append (res , principalSets )
191
+ }
192
+ if len (res ) == 0 {
193
+ return nil
194
+ }
195
+ return res [0 ]
196
+ }
197
+
198
+ func (ea * endorsementAnalyzer ) loadPolicies (chainID common.ChainID , interest * discovery.ChaincodeInterest ) ([]policies.InquireablePolicy , error ) {
199
+ var res []policies.InquireablePolicy
200
+ for _ , chaincode := range interest .Chaincodes {
201
+ pol := ea .PolicyByChaincode (string (chainID ), chaincode .Name )
202
+ if pol == nil {
203
+ logger .Debug ("Policy for chaincode '" , chaincode , "'doesn't exist" )
204
+ return nil , errors .New ("policy not found" )
205
+ }
206
+ res = append (res , pol )
207
+ }
208
+ return res , nil
209
+ }
210
+
211
+ type filterFunc func (policies.PrincipalSets ) (policies.PrincipalSets , error )
212
+
213
+ type filterFunctions []filterFunc
214
+
215
+ type metadataAndColFilter struct {
216
+ md []* chaincode.Metadata
217
+ filter filterFunc
218
+ }
219
+
220
+ func loadMetadataAndFilters (chainID common.ChainID , interest * discovery.ChaincodeInterest , fetch chaincodeMetadataFetcher ) (* metadataAndColFilter , error ) {
221
+ var metadata []* chaincode.Metadata
222
+ var filters filterFunctions
223
+
224
+ for _ , chaincode := range interest .Chaincodes {
225
+ ccMD := fetch .Metadata (string (chainID ), chaincode .Name , len (chaincode .CollectionNames ) > 0 )
226
+ if ccMD == nil {
227
+ return nil , errors .Errorf ("No metadata was found for chaincode %s in channel %s" , chaincode .Name , string (chainID ))
228
+ }
229
+ metadata = append (metadata , ccMD )
230
+ if len (chaincode .CollectionNames ) == 0 {
231
+ continue
232
+ }
233
+ f , err := newCollectionFilter (ccMD .CollectionsConfig )
234
+ if err != nil {
235
+ logger .Warningf ("Failed initializing collection filter for chaincode %s: %v" , chaincode .Name , err )
236
+ return nil , errors .WithStack (err )
237
+ }
238
+ filters = append (filters , f .forCollections (chaincode .Name , chaincode .CollectionNames ... ))
239
+ }
240
+
241
+ return computeFiltersWithMetadata (filters , metadata ), nil
242
+ }
243
+
244
+ func computeFiltersWithMetadata (filters filterFunctions , metadata []* chaincode.Metadata ) * metadataAndColFilter {
245
+ if len (filters ) == 0 {
246
+ return & metadataAndColFilter {
247
+ md : metadata ,
248
+ filter : noopFilter ,
249
+ }
250
+ }
251
+
252
+ return & metadataAndColFilter {
253
+ md : metadata ,
254
+ filter : filters .combine (),
255
+ }
256
+ }
257
+
258
+ func noopFilter (policies policies.PrincipalSets ) (policies.PrincipalSets , error ) {
259
+ return policies , nil
260
+ }
261
+
262
+ func (filters filterFunctions ) combine () filterFunc {
263
+ return func (principals policies.PrincipalSets ) (policies.PrincipalSets , error ) {
264
+ var err error
265
+ for _ , filter := range filters {
266
+ principals , err = filter (principals )
267
+ if err != nil {
268
+ return nil , err
269
+ }
270
+ }
271
+ return principals , nil
272
+ }
273
+ }
274
+
160
275
func (ea * endorsementAnalyzer ) satisfiesPrincipal (channel string , identitiesOfMembers memberIdentities ) peerPrincipalEvaluator {
161
276
return func (member discovery2.NetworkMember , principal * msp.MSPPrincipal ) bool {
162
277
err := ea .SatisfiesPrincipal (channel , identitiesOfMembers .identityByPKIID (member .PKIid ), principal )
@@ -373,17 +488,23 @@ func (l layouts) groupsSet() map[string]struct{} {
373
488
return m
374
489
}
375
490
376
- func peersWithChaincode (ccMD * chaincode.Metadata ) func (member discovery2.NetworkMember ) bool {
491
+ func peersWithChaincode (metadata ... * chaincode.Metadata ) func (member discovery2.NetworkMember ) bool {
377
492
return func (member discovery2.NetworkMember ) bool {
378
493
if member .Properties == nil {
379
494
return false
380
495
}
381
- for _ , cc := range member .Properties .Chaincodes {
382
- if cc .Name == ccMD .Name && cc .Version == ccMD .Version {
383
- return true
496
+ for _ , ccMD := range metadata {
497
+ var found bool
498
+ for _ , cc := range member .Properties .Chaincodes {
499
+ if cc .Name == ccMD .Name && cc .Version == ccMD .Version {
500
+ found = true
501
+ }
502
+ }
503
+ if ! found {
504
+ return false
384
505
}
385
506
}
386
- return false
507
+ return true
387
508
}
388
509
}
389
510
0 commit comments