158 lines
3.8 KiB
Go
158 lines
3.8 KiB
Go
/*
|
|
Copyright IBM Corp. All Rights Reserved.
|
|
|
|
SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
|
|
package discovery
|
|
|
|
import (
|
|
"math/rand"
|
|
"sort"
|
|
"time"
|
|
|
|
"github.com/hyperledger/fabric/gossip/protoext"
|
|
)
|
|
|
|
// Filter filters and sorts the given endorsers
|
|
type Filter interface {
|
|
Filter(endorsers Endorsers) Endorsers
|
|
}
|
|
|
|
// ExclusionFilter returns true if the given Peer
|
|
// is not to be considered when selecting peers
|
|
type ExclusionFilter interface {
|
|
// Exclude returns whether the given Peer is to be excluded or not
|
|
Exclude(Peer) bool
|
|
}
|
|
|
|
type selectionFunc func(Peer) bool
|
|
|
|
func (sf selectionFunc) Exclude(p Peer) bool {
|
|
return sf(p)
|
|
}
|
|
|
|
// PrioritySelector guides the selection of peers via
|
|
// giving peers a relative priority to their selection
|
|
type PrioritySelector interface {
|
|
// Compare compares between 2 peers and returns
|
|
// their relative scores
|
|
Compare(Peer, Peer) Priority
|
|
}
|
|
|
|
// Priority defines how likely a peer is to be selected
|
|
// over another peer.
|
|
// Positive priority means the left peer is selected
|
|
// Negative priority means the right peer is selected
|
|
// Zero priority means their priorities are the same
|
|
type Priority int
|
|
|
|
var (
|
|
// PrioritiesByHeight selects peers by descending height
|
|
PrioritiesByHeight = &byHeight{}
|
|
// NoExclusion accepts all peers and rejects no peers
|
|
NoExclusion = selectionFunc(noExclusion)
|
|
// NoPriorities is indifferent to how it selects peers
|
|
NoPriorities = &noPriorities{}
|
|
)
|
|
|
|
type noPriorities struct{}
|
|
|
|
func (nc noPriorities) Compare(_ Peer, _ Peer) Priority {
|
|
return 0
|
|
}
|
|
|
|
type byHeight struct{}
|
|
|
|
func (*byHeight) Compare(left Peer, right Peer) Priority {
|
|
leftHeight := left.StateInfoMessage.GetStateInfo().Properties.LedgerHeight
|
|
rightHeight := right.StateInfoMessage.GetStateInfo().Properties.LedgerHeight
|
|
|
|
if leftHeight > rightHeight {
|
|
return 1
|
|
}
|
|
if rightHeight > leftHeight {
|
|
return -1
|
|
}
|
|
return 0
|
|
}
|
|
|
|
func noExclusion(_ Peer) bool {
|
|
return false
|
|
}
|
|
|
|
// ExcludeHosts returns a ExclusionFilter that excludes the given endpoints
|
|
func ExcludeHosts(endpoints ...string) ExclusionFilter {
|
|
m := make(map[string]struct{})
|
|
for _, endpoint := range endpoints {
|
|
m[endpoint] = struct{}{}
|
|
}
|
|
return ExcludeByHost(func(host string) bool {
|
|
_, excluded := m[host]
|
|
return excluded
|
|
})
|
|
}
|
|
|
|
// ExcludeByHost creates a ExclusionFilter out of the given exclusion predicate
|
|
func ExcludeByHost(reject func(host string) bool) ExclusionFilter {
|
|
return selectionFunc(func(p Peer) bool {
|
|
endpoint := p.AliveMessage.GetAliveMsg().Membership.Endpoint
|
|
var internalEndpoint string
|
|
se := p.AliveMessage.GetSecretEnvelope()
|
|
if se != nil {
|
|
internalEndpoint = protoext.InternalEndpoint(se)
|
|
}
|
|
return reject(endpoint) || reject(internalEndpoint)
|
|
})
|
|
}
|
|
|
|
// Filter filters the endorsers according to the given ExclusionFilter
|
|
func (endorsers Endorsers) Filter(f ExclusionFilter) Endorsers {
|
|
var res Endorsers
|
|
for _, e := range endorsers {
|
|
if !f.Exclude(*e) {
|
|
res = append(res, e)
|
|
}
|
|
}
|
|
return res
|
|
}
|
|
|
|
// Shuffle sorts the endorsers in random order
|
|
func (endorsers Endorsers) Shuffle() Endorsers {
|
|
res := make(Endorsers, len(endorsers))
|
|
rand.Seed(time.Now().UnixNano())
|
|
for i, index := range rand.Perm(len(endorsers)) {
|
|
res[i] = endorsers[index]
|
|
}
|
|
return res
|
|
}
|
|
|
|
type endorserSort struct {
|
|
Endorsers
|
|
PrioritySelector
|
|
}
|
|
|
|
// Sort sorts the endorsers according to the given PrioritySelector
|
|
func (endorsers Endorsers) Sort(ps PrioritySelector) Endorsers {
|
|
sort.Sort(&endorserSort{
|
|
Endorsers: endorsers,
|
|
PrioritySelector: ps,
|
|
})
|
|
return endorsers
|
|
}
|
|
|
|
func (es *endorserSort) Len() int {
|
|
return len(es.Endorsers)
|
|
}
|
|
|
|
func (es *endorserSort) Less(i, j int) bool {
|
|
e1 := es.Endorsers[i]
|
|
e2 := es.Endorsers[j]
|
|
less := es.Compare(*e1, *e2)
|
|
return less > Priority(0)
|
|
}
|
|
|
|
func (es *endorserSort) Swap(i, j int) {
|
|
es.Endorsers[i], es.Endorsers[j] = es.Endorsers[j], es.Endorsers[i]
|
|
}
|