autopilot/interface+choice: add NodeScore type
We create a new type NodeScore which is a tuple (NodeID, score). The weightedChoice and chooseN algorithms are altered to expect this type. This is done in order to simplify the types we are using, since we were only using a subset of the fields in AttachmentDirective.
This commit is contained in:
parent
3739c19ef8
commit
25de66d27b
@ -571,22 +571,43 @@ func (a *Agent) openChans(availableFunds btcutil.Amount, numChans uint32,
|
||||
return fmt.Errorf("unable to calculate node scores : %v", err)
|
||||
}
|
||||
|
||||
// Add addresses to the candidates.
|
||||
for nID, c := range scores {
|
||||
addrs := addresses[nID]
|
||||
c.Addrs = addrs
|
||||
}
|
||||
|
||||
log.Debugf("Got scores for %d nodes", len(scores))
|
||||
|
||||
// Now use the score to make a weighted choice which
|
||||
// nodes to attempt to open channels to.
|
||||
chanCandidates, err := chooseN(numChans, scores)
|
||||
// Temporary convert to NodeScore.
|
||||
nodeScores := make(map[NodeID]*NodeScore)
|
||||
for k, v := range scores {
|
||||
nodeScores[k] = &NodeScore{
|
||||
NodeID: v.NodeID,
|
||||
Score: v.Score,
|
||||
}
|
||||
}
|
||||
|
||||
// Now use the score to make a weighted choice which nodes to attempt
|
||||
// to open channels to.
|
||||
nodeScores, err = chooseN(numChans, nodeScores)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Unable to make weighted choice: %v",
|
||||
err)
|
||||
}
|
||||
|
||||
chanCandidates := make(map[NodeID]*AttachmentDirective)
|
||||
for nID := range nodeScores {
|
||||
// Add addresses to the candidates.
|
||||
addrs := addresses[nID]
|
||||
|
||||
// If the node has no known addresses, we cannot connect to it,
|
||||
// so we'll skip it.
|
||||
if len(addrs) == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
chanCandidates[nID] = &AttachmentDirective{
|
||||
NodeID: nID,
|
||||
ChanAmt: chanSize,
|
||||
Addrs: addrs,
|
||||
}
|
||||
}
|
||||
|
||||
if len(chanCandidates) == 0 {
|
||||
log.Infof("No eligible candidates to connect to")
|
||||
return nil
|
||||
|
@ -46,10 +46,10 @@ func weightedChoice(w []float64) (int, error) {
|
||||
return 0, fmt.Errorf("unable to make choice")
|
||||
}
|
||||
|
||||
// chooseN picks at random min[n, len(s)] nodes if from the
|
||||
// AttachmentDirectives map, with a probability weighted by their score.
|
||||
func chooseN(n uint32, s map[NodeID]*AttachmentDirective) (
|
||||
map[NodeID]*AttachmentDirective, error) {
|
||||
// chooseN picks at random min[n, len(s)] nodes if from the NodeScore map, with
|
||||
// a probability weighted by their score.
|
||||
func chooseN(n uint32, s map[NodeID]*NodeScore) (
|
||||
map[NodeID]*NodeScore, error) {
|
||||
|
||||
// Keep track of the number of nodes not yet chosen, in addition to
|
||||
// their scores and NodeIDs.
|
||||
@ -65,7 +65,7 @@ func chooseN(n uint32, s map[NodeID]*AttachmentDirective) (
|
||||
|
||||
// Pick a weighted choice from the remaining nodes as long as there are
|
||||
// nodes left, and we haven't already picked n.
|
||||
chosen := make(map[NodeID]*AttachmentDirective)
|
||||
chosen := make(map[NodeID]*NodeScore)
|
||||
for len(chosen) < int(n) && rem > 0 {
|
||||
choice, err := weightedChoice(scores)
|
||||
if err == ErrNoPositive {
|
||||
|
@ -173,7 +173,7 @@ func TestWeightedChoiceDistribution(t *testing.T) {
|
||||
func TestChooseNEmptyMap(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
nodes := map[NodeID]*AttachmentDirective{}
|
||||
nodes := map[NodeID]*NodeScore{}
|
||||
property := func(n uint32) bool {
|
||||
res, err := chooseN(n, nodes)
|
||||
if err != nil {
|
||||
@ -191,12 +191,12 @@ func TestChooseNEmptyMap(t *testing.T) {
|
||||
|
||||
// candidateMapVarLen is a type we'll use to generate maps of various lengths
|
||||
// up to 255 to be used during QuickTests.
|
||||
type candidateMapVarLen map[NodeID]*AttachmentDirective
|
||||
type candidateMapVarLen map[NodeID]*NodeScore
|
||||
|
||||
// Generate generates a value of type candidateMapVarLen to be used during
|
||||
// QuickTests.
|
||||
func (candidateMapVarLen) Generate(rand *rand.Rand, size int) reflect.Value {
|
||||
nodes := make(map[NodeID]*AttachmentDirective)
|
||||
nodes := make(map[NodeID]*NodeScore)
|
||||
|
||||
// To avoid creating huge maps, we restrict them to max uint8 len.
|
||||
n := uint8(rand.Uint32())
|
||||
@ -212,7 +212,7 @@ func (candidateMapVarLen) Generate(rand *rand.Rand, size int) reflect.Value {
|
||||
|
||||
var nID [33]byte
|
||||
binary.BigEndian.PutUint32(nID[:], uint32(i))
|
||||
nodes[nID] = &AttachmentDirective{
|
||||
nodes[nID] = &NodeScore{
|
||||
Score: s,
|
||||
}
|
||||
}
|
||||
@ -226,7 +226,7 @@ func TestChooseNMinimum(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
// Helper to count the number of positive scores in the given map.
|
||||
numPositive := func(nodes map[NodeID]*AttachmentDirective) int {
|
||||
numPositive := func(nodes map[NodeID]*NodeScore) int {
|
||||
cnt := 0
|
||||
for _, v := range nodes {
|
||||
if v.Score > 0 {
|
||||
@ -274,7 +274,7 @@ func TestChooseNSample(t *testing.T) {
|
||||
const maxIterations = 100000
|
||||
fifth := uint32(numNodes / 5)
|
||||
|
||||
nodes := make(map[NodeID]*AttachmentDirective)
|
||||
nodes := make(map[NodeID]*NodeScore)
|
||||
|
||||
// we make 5 buckets of nodes: 0, 0.1, 0.2, 0.4 and 0.8 score. We want
|
||||
// to check that zero scores never gets chosen, while a doubling the
|
||||
@ -299,7 +299,7 @@ func TestChooseNSample(t *testing.T) {
|
||||
|
||||
var nID [33]byte
|
||||
binary.BigEndian.PutUint32(nID[:], i)
|
||||
nodes[nID] = &AttachmentDirective{
|
||||
nodes[nID] = &NodeScore{
|
||||
Score: s,
|
||||
}
|
||||
}
|
||||
|
@ -81,6 +81,18 @@ type ChannelGraph interface {
|
||||
ForEachNode(func(Node) error) error
|
||||
}
|
||||
|
||||
// NodeScore is a tuple mapping a NodeID to a score indicating the preference
|
||||
// of opening a channel with it.
|
||||
type NodeScore struct {
|
||||
// NodeID is the serialized compressed pubkey of the node that is being
|
||||
// scored.
|
||||
NodeID NodeID
|
||||
|
||||
// Score is the score given by the heuristic for opening a channel of
|
||||
// the given size to this node.
|
||||
Score float64
|
||||
}
|
||||
|
||||
// AttachmentDirective describes a channel attachment proscribed by an
|
||||
// AttachmentHeuristic. It details to which node a channel should be created
|
||||
// to, and also the parameters which should be used in the channel creation.
|
||||
|
Loading…
Reference in New Issue
Block a user