@@ -13,8 +13,8 @@ import (
13
13
"time"
14
14
15
15
"github.com/golang/protobuf/proto"
16
- "github.com/hyperledger/fabric/gossip/util"
17
16
"github.com/hyperledger/fabric/protos/discovery"
17
+ "github.com/hyperledger/fabric/protos/gossip"
18
18
"github.com/hyperledger/fabric/protos/msp"
19
19
"github.com/pkg/errors"
20
20
)
23
23
configTypes = []discovery.QueryType {discovery .ConfigQueryType , discovery .PeerMembershipQueryType , discovery .ChaincodeQueryType }
24
24
)
25
25
26
- type client struct {
26
+ // Client interacts with the discovery server
27
+ type Client struct {
27
28
lastRequest []byte
28
29
lastSignature []byte
29
30
createConnection Dialer
@@ -109,7 +110,7 @@ func (req *Request) addQueryMapping(queryType discovery.QueryType, key string) {
109
110
}
110
111
111
112
// Send sends the request and returns the response, or error on failure
112
- func (c * client ) Send (ctx context.Context , req * Request ) (Response , error ) {
113
+ func (c * Client ) Send (ctx context.Context , req * Request ) (Response , error ) {
113
114
req .Authentication = c .authInfo
114
115
payload , err := proto .Marshal (req .Request )
115
116
if err != nil {
@@ -119,7 +120,7 @@ func (c *client) Send(ctx context.Context, req *Request) (Response, error) {
119
120
sig := c .lastSignature
120
121
// Only sign the Request if it is different than the previous Request sent.
121
122
// Otherwise, use the last signature from the previous send.
122
- // This is not only to save CPU cycles in the client -side,
123
+ // This is not only to save CPU cycles in the Client -side,
123
124
// but also for the server side to be able to memoize the signature verification.
124
125
// We have the use the previous signature, because many signature schemes are not deterministic.
125
126
if ! bytes .Equal (c .lastRequest , payload ) {
@@ -201,7 +202,7 @@ func (cr *channelResponse) Peers() ([]*Peer, error) {
201
202
return nil , res .(error )
202
203
}
203
204
204
- func (cr * channelResponse ) Endorsers (cc string ) (Endorsers , error ) {
205
+ func (cr * channelResponse ) Endorsers (cc string , s Selector ) (Endorsers , error ) {
205
206
// If we have a key that has no chaincode field,
206
207
// it means it's an error returned from the service
207
208
if err , exists := cr .response [key {
@@ -224,18 +225,33 @@ func (cr *channelResponse) Endorsers(cc string) (Endorsers, error) {
224
225
225
226
desc := res .(* endorsementDescriptor )
226
227
rand .Seed (time .Now ().Unix ())
227
- randomLayoutIndex := rand .Intn (len (desc .layouts ))
228
- layout := desc .layouts [randomLayoutIndex ]
228
+ // We iterate over all layouts to find one that we have enough peers to select
229
+ for _ , index := range rand .Perm (len (desc .layouts )) {
230
+ layout := desc .layouts [index ]
231
+ endorsers , canLayoutBeSatisfied := selectPeersForLayout (desc .endorsersByGroups , layout , s )
232
+ if canLayoutBeSatisfied {
233
+ return endorsers , nil
234
+ }
235
+ }
236
+ return nil , errors .New ("no endorsement combination can be satisfied" )
237
+ }
238
+
239
+ func selectPeersForLayout (endorsersByGroups map [string ][]* Peer , layout map [string ]int , s Selector ) (Endorsers , bool ) {
229
240
var endorsers []* Peer
230
241
for grp , count := range layout {
231
- endorsersOfGrp := randomEndorsers (count , desc .endorsersByGroups [grp ])
242
+ shuffledEndorsers := Endorsers (endorsersByGroups [grp ]).Shuffle ()
243
+ endorsersOfGrp := s .Select (shuffledEndorsers )
244
+ // We couldn't select enough peers for this layout because the current group
245
+ // requires more peers than we have available to be selected
232
246
if len (endorsersOfGrp ) < count {
233
- return nil , errors . Errorf ( "layout has a group that requires at least %d peers, but only %d peers are known" , count , len ( endorsersOfGrp ))
247
+ return nil , false
234
248
}
249
+ endorsersOfGrp = endorsersOfGrp [:count ]
235
250
endorsers = append (endorsers , endorsersOfGrp ... )
236
251
}
237
-
238
- return endorsers , nil
252
+ // The current (randomly chosen) layout can be satisfied, so return it
253
+ // instead of checking the next one.
254
+ return endorsers , true
239
255
}
240
256
241
257
func (resp response ) ForChannel (ch string ) ChannelResponse {
@@ -330,6 +346,12 @@ func peersForChannel(membersRes *discovery.PeerMembershipResult) ([]*Peer, error
330
346
if err != nil {
331
347
return nil , errors .Wrap (err , "failed unmarshaling stateInfo message" )
332
348
}
349
+ if err := validateAliveMessage (aliveMsg ); err != nil {
350
+ return nil , errors .Wrap (err , "failed validating alive message" )
351
+ }
352
+ if err := validateStateInfoMessage (stateInfoMsg ); err != nil {
353
+ return nil , errors .Wrap (err , "failed validating stateInfo message" )
354
+ }
333
355
peers = append (peers , & Peer {
334
356
MSPID : org ,
335
357
Identity : peer .Identity ,
@@ -426,35 +448,63 @@ func endorser(peer *discovery.Peer, chaincode, channel string) (*Peer, error) {
426
448
if err != nil {
427
449
return nil , errors .Wrap (err , "failed unmarshaling gossip envelope to state info message" )
428
450
}
429
- sId := & msp.SerializedIdentity {}
430
- if err := proto .Unmarshal (peer .Identity , sId ); err != nil {
451
+ if err := validateAliveMessage (aliveMsg ); err != nil {
452
+ return nil , errors .Wrap (err , "failed validating alive message" )
453
+ }
454
+ if err := validateStateInfoMessage (stateInfMsg ); err != nil {
455
+ return nil , errors .Wrap (err , "failed validating stateInfo message" )
456
+ }
457
+ sID := & msp.SerializedIdentity {}
458
+ if err := proto .Unmarshal (peer .Identity , sID ); err != nil {
431
459
return nil , errors .Wrap (err , "failed unmarshaling peer's identity" )
432
460
}
433
461
return & Peer {
434
462
Identity : peer .Identity ,
435
463
StateInfoMessage : stateInfMsg ,
436
464
AliveMessage : aliveMsg ,
437
- MSPID : sId .Mspid ,
465
+ MSPID : sID .Mspid ,
438
466
}, nil
439
467
}
440
468
441
- func randomEndorsers (count int , totalPeers []* Peer ) Endorsers {
442
- var endorsers []* Peer
443
- for _ , index := range util .GetRandomIndices (count , len (totalPeers )- 1 ) {
444
- endorsers = append (endorsers , totalPeers [index ])
445
- }
446
- return endorsers
447
- }
448
-
449
469
type endorsementDescriptor struct {
450
470
endorsersByGroups map [string ][]* Peer
451
471
layouts []map [string ]int
452
472
}
453
473
454
- func NewClient (createConnection Dialer , authInfo * discovery.AuthInfo , s Signer ) * client {
455
- return & client {
474
+ // NewClient creates a new Client instance
475
+ func NewClient (createConnection Dialer , authInfo * discovery.AuthInfo , s Signer ) * Client {
476
+ return & Client {
456
477
createConnection : createConnection ,
457
478
authInfo : authInfo ,
458
479
signRequest : s ,
459
480
}
460
481
}
482
+
483
+ func validateAliveMessage (message * gossip.SignedGossipMessage ) error {
484
+ am := message .GetAliveMsg ()
485
+ if am == nil {
486
+ return errors .New ("message isn't an alive message" )
487
+ }
488
+ m := am .Membership
489
+ if m == nil {
490
+ return errors .New ("membership is empty" )
491
+ }
492
+ if am .Timestamp == nil {
493
+ return errors .New ("timestamp is nil" )
494
+ }
495
+ return nil
496
+ }
497
+
498
+ func validateStateInfoMessage (message * gossip.SignedGossipMessage ) error {
499
+ si := message .GetStateInfo ()
500
+ if si == nil {
501
+ return errors .New ("message isn't a stateInfo message" )
502
+ }
503
+ if si .Timestamp == nil {
504
+ return errors .New ("timestamp is nil" )
505
+ }
506
+ if si .Properties == nil {
507
+ return errors .New ("properties is nil" )
508
+ }
509
+ return nil
510
+ }
0 commit comments