autopilot/prefattach+interface: add API NodeScores
This commit adds a new method NodeScores to the AttachementHeuristic interface. Its intended use is to score a set of nodes according to their preference as channel counterparties. The PrefAttach heuristic gets a NodeScores method that will score the ndoes according to their number of already existing channels, similar to what is done already in Select.
This commit is contained in:
parent
5ecc209c41
commit
5e8e54083f
@ -93,6 +93,13 @@ func (m *mockHeuristic) Select(self *btcec.PublicKey, graph ChannelGraph,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (m *mockHeuristic) NodeScores(g ChannelGraph, chans []Channel,
|
||||||
|
fundsAvailable btcutil.Amount, nodes map[NodeID]struct{}) (
|
||||||
|
map[NodeID]*AttachmentDirective, error) {
|
||||||
|
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
var _ AttachmentHeuristic = (*mockHeuristic)(nil)
|
var _ AttachmentHeuristic = (*mockHeuristic)(nil)
|
||||||
|
|
||||||
type openChanIntent struct {
|
type openChanIntent struct {
|
||||||
|
@ -98,6 +98,10 @@ type AttachmentDirective struct {
|
|||||||
// Addrs is a list of addresses that the target peer may be reachable
|
// Addrs is a list of addresses that the target peer may be reachable
|
||||||
// at.
|
// at.
|
||||||
Addrs []net.Addr
|
Addrs []net.Addr
|
||||||
|
|
||||||
|
// Score is the score given by the heuristic for opening a channel of
|
||||||
|
// the given size to this node.
|
||||||
|
Score float64
|
||||||
}
|
}
|
||||||
|
|
||||||
// AttachmentHeuristic is one of the primary interfaces within this package.
|
// AttachmentHeuristic is one of the primary interfaces within this package.
|
||||||
@ -127,6 +131,24 @@ type AttachmentHeuristic interface {
|
|||||||
Select(self *btcec.PublicKey, graph ChannelGraph,
|
Select(self *btcec.PublicKey, graph ChannelGraph,
|
||||||
amtToUse btcutil.Amount, numNewChans uint32,
|
amtToUse btcutil.Amount, numNewChans uint32,
|
||||||
skipNodes map[NodeID]struct{}) ([]AttachmentDirective, error)
|
skipNodes map[NodeID]struct{}) ([]AttachmentDirective, error)
|
||||||
|
|
||||||
|
// NodeScores is a method that given the current channel graph, current
|
||||||
|
// set of local channels and funds available, scores the given nodes
|
||||||
|
// according to the preference of opening a channel with them. The
|
||||||
|
// returned channel candidates maps the NodeID to an attachemnt
|
||||||
|
// directive containing a score and a channel size.
|
||||||
|
//
|
||||||
|
// The scores will be in the range [0, M], where 0 indicates no
|
||||||
|
// improvement in connectivity if a channel is opened to this node,
|
||||||
|
// while M is the maximum possible improvement in connectivity. The
|
||||||
|
// size of M is up to the implementation of this interface, so scores
|
||||||
|
// must be normalized if compared against other implementations.
|
||||||
|
//
|
||||||
|
// NOTE: A NodeID not found in the returned map is implicitly given a
|
||||||
|
// score of 0.
|
||||||
|
NodeScores(g ChannelGraph, chans []Channel,
|
||||||
|
fundsAvailable btcutil.Amount, nodes map[NodeID]struct{}) (
|
||||||
|
map[NodeID]*AttachmentDirective, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ChannelController is a simple interface that allows an auto-pilot agent to
|
// ChannelController is a simple interface that allows an auto-pilot agent to
|
||||||
|
@ -4,6 +4,7 @@ import (
|
|||||||
"bytes"
|
"bytes"
|
||||||
"fmt"
|
"fmt"
|
||||||
prand "math/rand"
|
prand "math/rand"
|
||||||
|
"net"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/btcsuite/btcd/btcec"
|
"github.com/btcsuite/btcd/btcec"
|
||||||
@ -249,3 +250,108 @@ func (p *ConstrainedPrefAttachment) Select(self *btcec.PublicKey, g ChannelGraph
|
|||||||
return nil, fmt.Errorf("err")
|
return nil, fmt.Errorf("err")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NodeScores is a method that given the current channel graph, current set of
|
||||||
|
// local channels and funds available, scores the given nodes according the the
|
||||||
|
// preference of opening a channel with them.
|
||||||
|
//
|
||||||
|
// The heuristic employed by this method is one that attempts to promote a
|
||||||
|
// scale-free network globally, via local attachment preferences for new nodes
|
||||||
|
// joining the network with an amount of available funds to be allocated to
|
||||||
|
// channels. Specifically, we consider the degree of each node (and the flow
|
||||||
|
// in/out of the node available via its open channels) and utilize the
|
||||||
|
// Barabási–Albert model to drive our recommended attachment heuristics. If
|
||||||
|
// implemented globally for each new participant, this results in a channel
|
||||||
|
// graph that is scale-free and follows a power law distribution with k=-3.
|
||||||
|
//
|
||||||
|
// The returned scores will be in the range [0.0, 1.0], where higher scores are
|
||||||
|
// given to nodes already having high connectivity in the graph.
|
||||||
|
//
|
||||||
|
// NOTE: This is a part of the AttachmentHeuristic interface.
|
||||||
|
func (p *ConstrainedPrefAttachment) NodeScores(g ChannelGraph, chans []Channel,
|
||||||
|
fundsAvailable btcutil.Amount, nodes map[NodeID]struct{}) (
|
||||||
|
map[NodeID]*AttachmentDirective, error) {
|
||||||
|
|
||||||
|
// Count the number of channels in the graph. We'll also count the
|
||||||
|
// number of channels as we go for the nodes we are interested in, and
|
||||||
|
// record their addresses found in the db.
|
||||||
|
var graphChans int
|
||||||
|
nodeChanNum := make(map[NodeID]int)
|
||||||
|
addresses := make(map[NodeID][]net.Addr)
|
||||||
|
if err := g.ForEachNode(func(n Node) error {
|
||||||
|
var nodeChans int
|
||||||
|
err := n.ForEachChannel(func(_ ChannelEdge) error {
|
||||||
|
nodeChans++
|
||||||
|
graphChans++
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// If this node is not among our nodes to score, we can return
|
||||||
|
// early.
|
||||||
|
nID := NodeID(n.PubKey())
|
||||||
|
if _, ok := nodes[nID]; !ok {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Otherwise we'll record the number of channels, and also
|
||||||
|
// populate the address in our channel candidates map.
|
||||||
|
nodeChanNum[nID] = nodeChans
|
||||||
|
addresses[nID] = n.Addrs()
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// If there are no channels in the graph we cannot determine any
|
||||||
|
// preferences, so we return, indicating all candidates get a score of
|
||||||
|
// zero.
|
||||||
|
if graphChans == 0 {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
existingPeers := make(map[NodeID]struct{})
|
||||||
|
for _, c := range chans {
|
||||||
|
existingPeers[c.Node] = struct{}{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// For each node in the set of nodes, count their fraction of channels
|
||||||
|
// in the graph, and use that as the score.
|
||||||
|
candidates := make(map[NodeID]*AttachmentDirective)
|
||||||
|
for nID, nodeChans := range nodeChanNum {
|
||||||
|
// As channel size we'll use the maximum channel size available.
|
||||||
|
chanSize := p.constraints.MaxChanSize
|
||||||
|
if fundsAvailable-chanSize < 0 {
|
||||||
|
chanSize = fundsAvailable
|
||||||
|
}
|
||||||
|
|
||||||
|
_, ok := existingPeers[nID]
|
||||||
|
|
||||||
|
switch {
|
||||||
|
|
||||||
|
// If the node is among or existing channel peers, we don't
|
||||||
|
// need another channel.
|
||||||
|
case ok:
|
||||||
|
continue
|
||||||
|
|
||||||
|
// If the amount is too small, we don't want to attempt opening
|
||||||
|
// another channel.
|
||||||
|
case chanSize == 0 || chanSize < p.constraints.MinChanSize:
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// Otherwise we score the node according to its fraction of
|
||||||
|
// channels in the graph.
|
||||||
|
score := float64(nodeChans) / float64(graphChans)
|
||||||
|
candidates[nID] = &AttachmentDirective{
|
||||||
|
NodeID: nID,
|
||||||
|
ChanAmt: chanSize,
|
||||||
|
Score: score,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return candidates, nil
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user