github.com/decred/dcrlnd@v0.7.6/autopilot/externalscoreattach.go (about) 1 package autopilot 2 3 import ( 4 "fmt" 5 "sync" 6 7 "github.com/decred/dcrd/dcrutil/v4" 8 ) 9 10 // ExternalScoreAttachment is an implementation of the AttachmentHeuristic 11 // interface that allows an external source to provide it with node scores. 12 type ExternalScoreAttachment struct { 13 // TODO(halseth): persist across restarts. 14 nodeScores map[NodeID]float64 15 16 sync.Mutex 17 } 18 19 // NewExternalScoreAttachment creates a new instance of an 20 // ExternalScoreAttachment. 21 func NewExternalScoreAttachment() *ExternalScoreAttachment { 22 return &ExternalScoreAttachment{} 23 } 24 25 // A compile time assertion to ensure ExternalScoreAttachment meets the 26 // AttachmentHeuristic and ScoreSettable interfaces. 27 var _ AttachmentHeuristic = (*ExternalScoreAttachment)(nil) 28 var _ ScoreSettable = (*ExternalScoreAttachment)(nil) 29 30 // Name returns the name of this heuristic. 31 // 32 // NOTE: This is a part of the AttachmentHeuristic interface. 33 func (s *ExternalScoreAttachment) Name() string { 34 return "externalscore" 35 } 36 37 // SetNodeScores is used to set the internal map from NodeIDs to scores. The 38 // passed scores must be in the range [0, 1.0]. The fist parameter is the name 39 // of the targeted heuristic, to allow recursively target specific 40 // sub-heuristics. The returned boolean indicates whether the targeted 41 // heuristic was found. 42 // 43 // NOTE: This is a part of the ScoreSettable interface. 44 func (s *ExternalScoreAttachment) SetNodeScores(targetHeuristic string, 45 newScores map[NodeID]float64) (bool, error) { 46 47 // Return if this heuristic wasn't targeted. 48 if targetHeuristic != s.Name() { 49 return false, nil 50 } 51 52 // Since there's a requirement that all score are in the range [0, 53 // 1.0], we validate them before setting the internal list. 54 for nID, s := range newScores { 55 if s < 0 || s > 1.0 { 56 return false, fmt.Errorf("invalid score %v for "+ 57 "nodeID %v", s, nID) 58 } 59 } 60 61 s.Lock() 62 defer s.Unlock() 63 64 s.nodeScores = newScores 65 log.Tracef("Setting %v external scores", len(s.nodeScores)) 66 67 return true, nil 68 } 69 70 // NodeScores is a method that given the current channel graph and current set 71 // of local channels, scores the given nodes according to the preference of 72 // opening a channel of the given size with them. The returned channel 73 // candidates maps the NodeID to a NodeScore for the node. 74 // 75 // The returned scores will be in the range [0, 1.0], where 0 indicates no 76 // improvement in connectivity if a channel is opened to this node, while 1.0 77 // is the maximum possible improvement in connectivity. 78 // 79 // The scores are determined by checking the internal node scores list. Nodes 80 // not known will get a score of 0. 81 // 82 // NOTE: This is a part of the AttachmentHeuristic interface. 83 func (s *ExternalScoreAttachment) NodeScores(g ChannelGraph, chans []LocalChannel, 84 chanSize dcrutil.Amount, nodes map[NodeID]struct{}) ( 85 map[NodeID]*NodeScore, error) { 86 87 existingPeers := make(map[NodeID]struct{}) 88 for _, c := range chans { 89 existingPeers[c.Node] = struct{}{} 90 } 91 92 s.Lock() 93 defer s.Unlock() 94 95 log.Tracef("External scoring %v nodes, from %v set scores", 96 len(nodes), len(s.nodeScores)) 97 98 // Fill the map of candidates to return. 99 candidates := make(map[NodeID]*NodeScore) 100 for nID := range nodes { 101 var score float64 102 if nodeScore, ok := s.nodeScores[nID]; ok { 103 score = nodeScore 104 } 105 106 // If the node is among or existing channel peers, we don't 107 // need another channel. 108 if _, ok := existingPeers[nID]; ok { 109 log.Tracef("Skipping existing peer %x from external "+ 110 "score results", nID[:]) 111 continue 112 } 113 114 log.Tracef("External score %v given to node %x", score, nID[:]) 115 116 // Instead of adding a node with score 0 to the returned set, 117 // we just skip it. 118 if score == 0 { 119 continue 120 } 121 122 candidates[nID] = &NodeScore{ 123 NodeID: nID, 124 Score: score, 125 } 126 } 127 128 return candidates, nil 129 }