autopilot: add ExternalScoreAttachment heuristic
This commit adds a new autopilot heuristic that is scoring based. It is a simple heuristic that will keep a list of pubkeys and scores, and will try opening channels with the nodes with the largest score first.
This commit is contained in:
parent
e10fe91f10
commit
dff61facf2
119
autopilot/externalscoreattach.go
Normal file
119
autopilot/externalscoreattach.go
Normal file
@ -0,0 +1,119 @@
|
||||
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 interface.
|
||||
var _ AttachmentHeuristic = (*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.
|
||||
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
|
||||
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 []Channel,
|
||||
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()
|
||||
|
||||
// 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 = float64(nodeScore)
|
||||
}
|
||||
|
||||
_, ok := existingPeers[nID]
|
||||
switch {
|
||||
|
||||
// If the node is among or existing channel peers, we don't
|
||||
// need another channel.
|
||||
case ok:
|
||||
continue
|
||||
|
||||
// Instead of adding a node with score 0 to the returned set,
|
||||
// we just skip it.
|
||||
case score == 0:
|
||||
continue
|
||||
}
|
||||
|
||||
candidates[nID] = &NodeScore{
|
||||
NodeID: nID,
|
||||
Score: score,
|
||||
}
|
||||
}
|
||||
|
||||
return candidates, nil
|
||||
}
|
@ -147,6 +147,7 @@ var (
|
||||
// with the autopilot agent.
|
||||
availableHeuristics = []AttachmentHeuristic{
|
||||
NewPrefAttachment(),
|
||||
NewExternalScoreAttachment(),
|
||||
}
|
||||
|
||||
// AvailableHeuristics is a map that holds the name of available
|
||||
|
Loading…
Reference in New Issue
Block a user