@@ -79,14 +79,18 @@ type peerPrincipalEvaluator func(member discovery2.NetworkMember, principal *msp
7979
8080// PeersForEndorsement returns an EndorsementDescriptor for a given set of peers, channel, and chaincode
8181func (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 )
8791 }
8892 // 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 ... ))
9094 channelMembersById := chanMembership .ByID ()
9195 // Choose only the alive messages of those that have joined the channel
9296 aliveMembership := ea .Peers ().Intersect (chanMembership )
@@ -95,68 +99,179 @@ func (ea *endorsementAnalyzer) PeersForEndorsement(chainID common.ChainID, inter
9599 identities := ea .IdentityInfo ()
96100 identitiesOfMembers := computeIdentitiesOfMembers (identities , membersById )
97101
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 )
103106 }
107+ // For now we take the first policy and ignore the rest
108+ pol := pols [0 ]
104109
105110 // Compute the combinations of principals (principal sets) that satisfy the endorsement policy
106111 principalsSets := policies .PrincipalSets (pol .SatisfiedBy ())
107112
108- // Obtain the MSP IDs of the members of the channel that are alive
109- mspIDsOfChannelPeers := mspIDsOfMembers (membersById , identities .ByID ())
110113 // 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 ())
116115
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 )
128120 }
129121
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 ) {
130142 // mapPrincipalsToGroups returns a mapping from principals to their corresponding groups.
131143 // groups are just human readable representations that mask the principals behind them
132- principalGroups := mapPrincipalsToGroups (principalsSets )
144+ principalGroups := mapPrincipalsToGroups (ctx . principalsSets )
133145 // principalsToPeersGraph computes a bipartite graph (V1 U V2 , E)
134146 // such that V1 is the peers, V2 are the principals,
135147 // and each e=(peer,principal) is in E if the peer satisfies the principal
136148 satGraph := principalsToPeersGraph (principalAndPeerData {
137- members : aliveMembership ,
149+ members : ctx . aliveMembership ,
138150 pGrps : principalGroups ,
139- }, ea .satisfiesPrincipal (string ( chainID ), identitiesOfMembers ))
151+ }, ea .satisfiesPrincipal (ctx . channel , ctx . identitiesOfMembers ))
140152
141- layouts := computeLayouts (principalsSets , principalGroups , satGraph )
153+ layouts := computeLayouts (ctx . principalsSets , principalGroups , satGraph )
142154 if len (layouts ) == 0 {
143155 return nil , errors .New ("cannot satisfy any principal combination" )
144156 }
145157
146158 criteria := & peerMembershipCriteria {
147159 possibleLayouts : layouts ,
148160 satGraph : satGraph ,
149- chanMemberById : channelMembersById ,
150- idOfMembers : identitiesOfMembers ,
161+ chanMemberById : ctx . channelMembersById ,
162+ idOfMembers : ctx . identitiesOfMembers ,
151163 }
152164
153165 return & discovery.EndorsementDescriptor {
154- Chaincode : chaincode . Name ,
166+ Chaincode : ctx . chaincode ,
155167 Layouts : layouts ,
156168 EndorsersByGroups : endorsersByGroup (criteria ),
157169 }, nil
158170}
159171
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+
160275func (ea * endorsementAnalyzer ) satisfiesPrincipal (channel string , identitiesOfMembers memberIdentities ) peerPrincipalEvaluator {
161276 return func (member discovery2.NetworkMember , principal * msp.MSPPrincipal ) bool {
162277 err := ea .SatisfiesPrincipal (channel , identitiesOfMembers .identityByPKIID (member .PKIid ), principal )
@@ -373,17 +488,23 @@ func (l layouts) groupsSet() map[string]struct{} {
373488 return m
374489}
375490
376- func peersWithChaincode (ccMD * chaincode.Metadata ) func (member discovery2.NetworkMember ) bool {
491+ func peersWithChaincode (metadata ... * chaincode.Metadata ) func (member discovery2.NetworkMember ) bool {
377492 return func (member discovery2.NetworkMember ) bool {
378493 if member .Properties == nil {
379494 return false
380495 }
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
384505 }
385506 }
386- return false
507+ return true
387508 }
388509}
389510
0 commit comments