You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
129 lines
3.7 KiB
129 lines
3.7 KiB
package autopilot |
|
|
|
import ( |
|
"fmt" |
|
"sync" |
|
|
|
"github.com/btcsuite/btcutil" |
|
) |
|
|
|
// ExternalScoreAttachment is an implementation of the AttachmentHeuristic |
|
// interface that allows an external source to provide it with node scores. |
|
type ExternalScoreAttachment struct { |
|
// TODO(halseth): persist across restarts. |
|
nodeScores map[NodeID]float64 |
|
|
|
sync.Mutex |
|
} |
|
|
|
// NewExternalScoreAttachment creates a new instance of an |
|
// ExternalScoreAttachment. |
|
func NewExternalScoreAttachment() *ExternalScoreAttachment { |
|
return &ExternalScoreAttachment{} |
|
} |
|
|
|
// A compile time assertion to ensure ExternalScoreAttachment meets the |
|
// AttachmentHeuristic and ScoreSettable interfaces. |
|
var _ AttachmentHeuristic = (*ExternalScoreAttachment)(nil) |
|
var _ ScoreSettable = (*ExternalScoreAttachment)(nil) |
|
|
|
// Name returns the name of this heuristic. |
|
// |
|
// NOTE: This is a part of the AttachmentHeuristic interface. |
|
func (s *ExternalScoreAttachment) Name() string { |
|
return "externalscore" |
|
} |
|
|
|
// SetNodeScores is used to set the internal map from NodeIDs to scores. The |
|
// passed scores must be in the range [0, 1.0]. The fist parameter is the name |
|
// of the targeted heuristic, to allow recursively target specific |
|
// sub-heuristics. The returned boolean indicates whether the targeted |
|
// heuristic was found. |
|
// |
|
// NOTE: This is a part of the ScoreSettable interface. |
|
func (s *ExternalScoreAttachment) SetNodeScores(targetHeuristic string, |
|
newScores map[NodeID]float64) (bool, error) { |
|
|
|
// Return if this heuristic wasn't targeted. |
|
if targetHeuristic != s.Name() { |
|
return false, nil |
|
} |
|
|
|
// Since there's a requirement that all score are in the range [0, |
|
// 1.0], we validate them before setting the internal list. |
|
for nID, s := range newScores { |
|
if s < 0 || s > 1.0 { |
|
return false, fmt.Errorf("invalid score %v for "+ |
|
"nodeID %v", s, nID) |
|
} |
|
} |
|
|
|
s.Lock() |
|
defer s.Unlock() |
|
|
|
s.nodeScores = newScores |
|
log.Tracef("Setting %v external scores", len(s.nodeScores)) |
|
|
|
return true, nil |
|
} |
|
|
|
// NodeScores is a method that given the current channel graph and current set |
|
// of local channels, scores the given nodes according to the preference of |
|
// opening a channel of the given size with them. The returned channel |
|
// candidates maps the NodeID to a NodeScore for the node. |
|
// |
|
// The returned scores will be in the range [0, 1.0], where 0 indicates no |
|
// improvement in connectivity if a channel is opened to this node, while 1.0 |
|
// is the maximum possible improvement in connectivity. |
|
// |
|
// The scores are determined by checking the internal node scores list. Nodes |
|
// not known will get a score of 0. |
|
// |
|
// NOTE: This is a part of the AttachmentHeuristic interface. |
|
func (s *ExternalScoreAttachment) NodeScores(g ChannelGraph, chans []LocalChannel, |
|
chanSize btcutil.Amount, nodes map[NodeID]struct{}) ( |
|
map[NodeID]*NodeScore, error) { |
|
|
|
existingPeers := make(map[NodeID]struct{}) |
|
for _, c := range chans { |
|
existingPeers[c.Node] = struct{}{} |
|
} |
|
|
|
s.Lock() |
|
defer s.Unlock() |
|
|
|
log.Tracef("External scoring %v nodes, from %v set scores", |
|
len(nodes), len(s.nodeScores)) |
|
|
|
// Fill the map of candidates to return. |
|
candidates := make(map[NodeID]*NodeScore) |
|
for nID := range nodes { |
|
var score float64 |
|
if nodeScore, ok := s.nodeScores[nID]; ok { |
|
score = nodeScore |
|
} |
|
|
|
// If the node is among or existing channel peers, we don't |
|
// need another channel. |
|
if _, ok := existingPeers[nID]; ok { |
|
log.Tracef("Skipping existing peer %x from external "+ |
|
"score results", nID[:]) |
|
continue |
|
} |
|
|
|
log.Tracef("External score %v given to node %x", score, nID[:]) |
|
|
|
// Instead of adding a node with score 0 to the returned set, |
|
// we just skip it. |
|
if score == 0 { |
|
continue |
|
} |
|
|
|
candidates[nID] = &NodeScore{ |
|
NodeID: nID, |
|
Score: score, |
|
} |
|
} |
|
|
|
return candidates, nil |
|
}
|
|
|