autopilot: shuffle set of candidates using Fisher–Yates before selecting

In this commit we modify the ConstrainedPrefAttachment.Select method to
first shuffle the set of potential candidates before selecting them.
This serves to remove the existing grouping between candidates which
may have influenced the selection.
This commit is contained in:
Olaoluwa Osuntokun 2017-10-30 18:55:48 -07:00
parent 5ced45af01
commit 9bcb139bcc
No known key found for this signature in database
GPG Key ID: 964EA263DD637C21

View File

@ -107,6 +107,21 @@ func NewNodeID(pub *btcec.PublicKey) NodeID {
return n
}
// shuffleCandidates shuffles the set of candidate nodes for preferential
// attachment in order to break any ordering already enforced by the sorted
// order of the public key for each node. To shuffle the set of candidates, we
// use a version of the FisherYates shuffle algorithm.
func shuffleCandidates(candidates []Node) []Node {
shuffledNodes := make([]Node, len(candidates))
perm := prand.Perm(len(candidates))
for i, v := range perm {
shuffledNodes[v] = candidates[i]
}
return shuffledNodes
}
// Select returns a candidate set of attachment directives that should be
// executed based on the current internal state, the state of the channel
// graph, the set of nodes we should exclude, and the amount of funds
@ -208,8 +223,9 @@ func (p *ConstrainedPrefAttachment) Select(self *btcec.PublicKey, g ChannelGraph
// Given our selection slice, we'll now generate a random index
// into this slice. The node we select will be recommended by
// us to create a channel to.
selectedIndex := prand.Int31n(int32(len(selectionSlice)))
selectedNode := selectionSlice[selectedIndex]
candidates := shuffleCandidates(selectionSlice)
selectedIndex := prand.Int31n(int32(len(candidates)))
selectedNode := candidates[selectedIndex]
// TODO(roasbeef): cap on num channels to same participant?