autopilot: move determining chanSize from heuristic to agent

Since we want to combine scores from multiple heuristics, things get
complicated if the heuristics report their own individual channel sizes.
Therefore we change the NodeScores interface slightly, letting the agent
specify the wanted channel size, and let the heuristic score the nodes
accordingly.
This commit is contained in:
Johan T. Halseth 2018-12-19 14:54:53 +01:00
parent d5f3714f86
commit cfd237bf1f
No known key found for this signature in database
GPG Key ID: 15BAADA29DA20D26
4 changed files with 27 additions and 32 deletions

@ -547,10 +547,16 @@ func (a *Agent) openChans(availableFunds btcutil.Amount, numChans uint32,
return fmt.Errorf("unable to get graph nodes: %v", err) return fmt.Errorf("unable to get graph nodes: %v", err)
} }
// As channel size we'll use the maximum channel size available.
chanSize := a.cfg.Constraints.MaxChanSize()
if availableFunds-chanSize < 0 {
chanSize = availableFunds
}
// Use the heuristic to calculate a score for each node in the // Use the heuristic to calculate a score for each node in the
// graph. // graph.
scores, err := a.cfg.Heuristic.NodeScores( scores, err := a.cfg.Heuristic.NodeScores(
a.cfg.Graph, totalChans, availableFunds, nodes, a.cfg.Graph, totalChans, chanSize, nodes,
) )
if err != nil { if err != nil {
return fmt.Errorf("unable to calculate node scores : %v", err) return fmt.Errorf("unable to calculate node scores : %v", err)

@ -111,11 +111,11 @@ type AttachmentDirective struct {
// the interface is to allow an auto-pilot agent to decide if it needs more // the interface is to allow an auto-pilot agent to decide if it needs more
// channels, and if so, which exact channels should be opened. // channels, and if so, which exact channels should be opened.
type AttachmentHeuristic interface { type AttachmentHeuristic interface {
// NodeScores is a method that given the current channel graph, current // NodeScores is a method that given the current channel graph and
// set of local channels and funds available, scores the given nodes // current set of local channels, scores the given nodes according to
// according to the preference of opening a channel with them. The // the preference of opening a channel of the given size with them. The
// returned channel candidates maps the NodeID to an attachemnt // returned channel candidates maps the NodeID to an attachment
// directive containing a score and a channel size. // directive containing a score.
// //
// The scores will be in the range [0, M], where 0 indicates no // The scores will be in the range [0, M], where 0 indicates no
// improvement in connectivity if a channel is opened to this node, // improvement in connectivity if a channel is opened to this node,
@ -126,7 +126,7 @@ type AttachmentHeuristic interface {
// NOTE: A NodeID not found in the returned map is implicitly given a // NOTE: A NodeID not found in the returned map is implicitly given a
// score of 0. // score of 0.
NodeScores(g ChannelGraph, chans []Channel, NodeScores(g ChannelGraph, chans []Channel,
fundsAvailable btcutil.Amount, nodes map[NodeID]struct{}) ( chanSize btcutil.Amount, nodes map[NodeID]struct{}) (
map[NodeID]*AttachmentDirective, error) map[NodeID]*AttachmentDirective, error)
} }

@ -53,9 +53,9 @@ func NewNodeID(pub *btcec.PublicKey) NodeID {
return n return n
} }
// NodeScores is a method that given the current channel graph, current set of // NodeScores is a method that given the current channel graph and
// local channels and funds available, scores the given nodes according the the // current set of local channels, scores the given nodes according to
// preference of opening a channel with them. // the preference of opening a channel of the given size with them.
// //
// The heuristic employed by this method is one that attempts to promote a // The heuristic employed by this method is one that attempts to promote a
// scale-free network globally, via local attachment preferences for new nodes // scale-free network globally, via local attachment preferences for new nodes
@ -71,7 +71,7 @@ func NewNodeID(pub *btcec.PublicKey) NodeID {
// //
// NOTE: This is a part of the AttachmentHeuristic interface. // NOTE: This is a part of the AttachmentHeuristic interface.
func (p *ConstrainedPrefAttachment) NodeScores(g ChannelGraph, chans []Channel, func (p *ConstrainedPrefAttachment) NodeScores(g ChannelGraph, chans []Channel,
fundsAvailable btcutil.Amount, nodes map[NodeID]struct{}) ( chanSize btcutil.Amount, nodes map[NodeID]struct{}) (
map[NodeID]*AttachmentDirective, error) { map[NodeID]*AttachmentDirective, error) {
// Count the number of channels in the graph. We'll also count the // Count the number of channels in the graph. We'll also count the
@ -124,11 +124,6 @@ func (p *ConstrainedPrefAttachment) NodeScores(g ChannelGraph, chans []Channel,
// in the graph, and use that as the score. // in the graph, and use that as the score.
candidates := make(map[NodeID]*AttachmentDirective) candidates := make(map[NodeID]*AttachmentDirective)
for nID, nodeChans := range nodeChanNum { 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] _, ok := existingPeers[nID]
addrs := addresses[nID] addrs := addresses[nID]
@ -140,11 +135,6 @@ func (p *ConstrainedPrefAttachment) NodeScores(g ChannelGraph, chans []Channel,
case ok: case ok:
continue continue
// If the amount is too small, we don't want to attempt opening
// another channel.
case chanSize == 0 || chanSize < p.constraints.MinChanSize():
continue
// If the node has no addresses, we cannot connect to it, so we // If the node has no addresses, we cannot connect to it, so we
// skip it for now, which implicitly gives it a score of 0. // skip it for now, which implicitly gives it a score of 0.
case len(addrs) == 0: case len(addrs) == 0:

@ -241,9 +241,8 @@ func TestConstrainedPrefAttachmentSelectTwoVertexes(t *testing.T) {
// With the necessary state initialized, we'll now // With the necessary state initialized, we'll now
// attempt to get our candidates channel score given // attempt to get our candidates channel score given
// the current state of the graph. // the current state of the graph.
const walletFunds = btcutil.SatoshiPerBitcoin * 10
candidates, err := prefAttach.NodeScores(graph, nil, candidates, err := prefAttach.NodeScores(graph, nil,
walletFunds, nodes) maxChanSize, nodes)
if err != nil { if err != nil {
t1.Fatalf("unable to select attachment "+ t1.Fatalf("unable to select attachment "+
"directives: %v", err) "directives: %v", err)
@ -351,7 +350,7 @@ func TestConstrainedPrefAttachmentSelectInsufficientFunds(t *testing.T) {
// With the necessary state initialized, we'll now // With the necessary state initialized, we'll now
// attempt to get the score for our list of nodes, // attempt to get the score for our list of nodes,
// passing zero for the amount of wallet funds. This // passing zero for the amount of wallet funds. This
// should return an all-zero score set. // should return candidates with zero-value channels.
scores, err := prefAttach.NodeScores(graph, nil, scores, err := prefAttach.NodeScores(graph, nil,
0, nodes) 0, nodes)
if err != nil { if err != nil {
@ -361,9 +360,11 @@ func TestConstrainedPrefAttachmentSelectInsufficientFunds(t *testing.T) {
// Since all should be given a score of 0, the map // Since all should be given a score of 0, the map
// should be empty. // should be empty.
if len(scores) != 0 { for _, s := range scores {
t1.Fatalf("expected empty score map, "+ if s.ChanAmt != 0 {
"instead got %v ", len(scores)) t1.Fatalf("expected zero channel, "+
"instead got %v ", s.ChanAmt)
}
} }
}) })
if !success { if !success {
@ -466,9 +467,8 @@ func TestConstrainedPrefAttachmentSelectGreedyAllocation(t *testing.T) {
// 50/50 allocation, and have 3 BTC in channels. As a // 50/50 allocation, and have 3 BTC in channels. As a
// result, the heuristic should try to greedily // result, the heuristic should try to greedily
// allocate funds to channels. // allocate funds to channels.
const availableBalance = btcutil.SatoshiPerBitcoin * 2.5
scores, err := prefAttach.NodeScores(graph, nil, scores, err := prefAttach.NodeScores(graph, nil,
availableBalance, nodes) maxChanSize, nodes)
if err != nil { if err != nil {
t1.Fatalf("unable to select attachment "+ t1.Fatalf("unable to select attachment "+
"directives: %v", err) "directives: %v", err)
@ -598,9 +598,8 @@ func TestConstrainedPrefAttachmentSelectSkipNodes(t *testing.T) {
// With our graph created, we'll now get the scores for // With our graph created, we'll now get the scores for
// all nodes in the graph. // all nodes in the graph.
const availableBalance = btcutil.SatoshiPerBitcoin * 2.5
scores, err := prefAttach.NodeScores(graph, nil, scores, err := prefAttach.NodeScores(graph, nil,
availableBalance, nodes) maxChanSize, nodes)
if err != nil { if err != nil {
t1.Fatalf("unable to select attachment "+ t1.Fatalf("unable to select attachment "+
"directives: %v", err) "directives: %v", err)
@ -646,7 +645,7 @@ func TestConstrainedPrefAttachmentSelectSkipNodes(t *testing.T) {
// then all nodes should have a score of zero, since we // then all nodes should have a score of zero, since we
// already got channels to them. // already got channels to them.
scores, err = prefAttach.NodeScores(graph, chans, scores, err = prefAttach.NodeScores(graph, chans,
availableBalance, nodes) maxChanSize, nodes)
if err != nil { if err != nil {
t1.Fatalf("unable to select attachment "+ t1.Fatalf("unable to select attachment "+
"directives: %v", err) "directives: %v", err)