From 55ba5fe654ec25621612a47162b09900a5b291a3 Mon Sep 17 00:00:00 2001 From: "Johan T. Halseth" Date: Mon, 10 Dec 2018 14:56:54 +0100 Subject: [PATCH 1/6] autopilot/graph: add addresses to memNode --- autopilot/graph.go | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/autopilot/graph.go b/autopilot/graph.go index 4fbd02960..5ee547378 100644 --- a/autopilot/graph.go +++ b/autopilot/graph.go @@ -335,6 +335,11 @@ func (m *memChannelGraph) addRandChannel(node1, node2 *btcec.PublicKey, if !ok { vertex1 = memNode{ pub: node1, + addrs: []net.Addr{ + &net.TCPAddr{ + IP: bytes.Repeat([]byte("a"), 16), + }, + }, } } } else { @@ -344,6 +349,11 @@ func (m *memChannelGraph) addRandChannel(node1, node2 *btcec.PublicKey, } vertex1 = memNode{ pub: newPub, + addrs: []net.Addr{ + &net.TCPAddr{ + IP: bytes.Repeat([]byte("a"), 16), + }, + }, } } @@ -352,6 +362,11 @@ func (m *memChannelGraph) addRandChannel(node1, node2 *btcec.PublicKey, if !ok { vertex2 = memNode{ pub: node2, + addrs: []net.Addr{ + &net.TCPAddr{ + IP: bytes.Repeat([]byte("a"), 16), + }, + }, } } } else { @@ -361,6 +376,11 @@ func (m *memChannelGraph) addRandChannel(node1, node2 *btcec.PublicKey, } vertex2 = memNode{ pub: newPub, + addrs: []net.Addr{ + &net.TCPAddr{ + IP: bytes.Repeat([]byte("a"), 16), + }, + }, } } From d9eef4625e392de4a14800f6da3038329837a855 Mon Sep 17 00:00:00 2001 From: "Johan T. Halseth" Date: Mon, 10 Dec 2018 14:56:54 +0100 Subject: [PATCH 2/6] autopilot/prefattach: populate Addrs field --- autopilot/prefattach.go | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/autopilot/prefattach.go b/autopilot/prefattach.go index d90437b89..32bd2fcc5 100644 --- a/autopilot/prefattach.go +++ b/autopilot/prefattach.go @@ -148,6 +148,7 @@ func (p *ConstrainedPrefAttachment) NodeScores(g ChannelGraph, chans []Channel, } _, ok := existingPeers[nID] + addrs := addresses[nID] switch { @@ -160,6 +161,11 @@ func (p *ConstrainedPrefAttachment) NodeScores(g ChannelGraph, chans []Channel, // another channel. case chanSize == 0 || chanSize < p.constraints.MinChanSize: continue + + // 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. + case len(addrs) == 0: + continue } // Otherwise we score the node according to its fraction of @@ -168,6 +174,7 @@ func (p *ConstrainedPrefAttachment) NodeScores(g ChannelGraph, chans []Channel, candidates[nID] = &AttachmentDirective{ NodeID: nID, ChanAmt: chanSize, + Addrs: addrs, Score: score, } } From 5224c94aafbf54a80a9aa1aa5db676add89ab7ba Mon Sep 17 00:00:00 2001 From: "Johan T. Halseth" Date: Mon, 10 Dec 2018 14:56:54 +0100 Subject: [PATCH 3/6] autopilot/prefattach_test: assert scored nodes having addresses This addtion to the test makes sure the scored nodes have their addresses populated. This would fail without the previous commit. --- autopilot/prefattach_test.go | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/autopilot/prefattach_test.go b/autopilot/prefattach_test.go index adaee08b7..c647c2d92 100644 --- a/autopilot/prefattach_test.go +++ b/autopilot/prefattach_test.go @@ -436,6 +436,11 @@ func TestConstrainedPrefAttachmentSelectTwoVertexes(t *testing.T) { "to be %v, instead was %v", expScore, candidate.Score) } + + if len(candidate.Addrs) == 0 { + t1.Fatalf("expected node to have " + + "available addresses, didn't") + } } }) if !success { @@ -633,6 +638,11 @@ func TestConstrainedPrefAttachmentSelectGreedyAllocation(t *testing.T) { "of %v, instead got %v", maxChanSize, candidate.ChanAmt) } + + if len(candidate.Addrs) == 0 { + t1.Fatalf("expected node to have " + + "available addresses, didn't") + } } // Imagine a few channels are being opened, and there's @@ -663,6 +673,11 @@ func TestConstrainedPrefAttachmentSelectGreedyAllocation(t *testing.T) { "of %v, instead got %v", remBalance, candidate.ChanAmt) } + + if len(candidate.Addrs) == 0 { + t1.Fatalf("expected node to have " + + "available addresses, didn't") + } } }) if !success { @@ -753,6 +768,11 @@ func TestConstrainedPrefAttachmentSelectSkipNodes(t *testing.T) { "of %v, instead got %v", maxChanSize, candidate.ChanAmt) } + + if len(candidate.Addrs) == 0 { + t1.Fatalf("expected node to have " + + "available addresses, didn't") + } } // We'll simulate a channel update by adding the nodes From aeeff4714d3279357342c7c5438108b570f9ded3 Mon Sep 17 00:00:00 2001 From: "Johan T. Halseth" Date: Mon, 10 Dec 2018 14:56:54 +0100 Subject: [PATCH 4/6] autopilot/graph: define addRandNode --- autopilot/graph.go | 42 ++++++++++++++++++++++++++++++++++++ autopilot/prefattach_test.go | 2 ++ 2 files changed, 44 insertions(+) diff --git a/autopilot/graph.go b/autopilot/graph.go index 5ee547378..15440caf7 100644 --- a/autopilot/graph.go +++ b/autopilot/graph.go @@ -270,6 +270,30 @@ func (d *databaseChannelGraph) addRandChannel(node1, node2 *btcec.PublicKey, nil } +func (d *databaseChannelGraph) addRandNode() (*btcec.PublicKey, error) { + nodeKey, err := randKey() + if err != nil { + return nil, err + } + dbNode := &channeldb.LightningNode{ + HaveNodeAnnouncement: true, + Addresses: []net.Addr{ + &net.TCPAddr{ + IP: bytes.Repeat([]byte("a"), 16), + }, + }, + Features: lnwire.NewFeatureVector(nil, lnwire.GlobalFeatures), + AuthSigBytes: testSig.Serialize(), + } + dbNode.AddPubKey(nodeKey) + if err := d.db.AddLightningNode(dbNode); err != nil { + return nil, err + } + + return nodeKey, nil + +} + // memChannelGraph is an implementation of the autopilot.ChannelGraph backed by // an in-memory graph. type memChannelGraph struct { @@ -407,6 +431,24 @@ func (m *memChannelGraph) addRandChannel(node1, node2 *btcec.PublicKey, return &edge1, &edge2, nil } +func (m *memChannelGraph) addRandNode() (*btcec.PublicKey, error) { + newPub, err := randKey() + if err != nil { + return nil, err + } + vertex := memNode{ + pub: newPub, + addrs: []net.Addr{ + &net.TCPAddr{ + IP: bytes.Repeat([]byte("a"), 16), + }, + }, + } + m.graph[NewNodeID(newPub)] = vertex + + return newPub, nil +} + // memNode is a purely in-memory implementation of the autopilot.Node // interface. type memNode struct { diff --git a/autopilot/prefattach_test.go b/autopilot/prefattach_test.go index c647c2d92..5801c00de 100644 --- a/autopilot/prefattach_test.go +++ b/autopilot/prefattach_test.go @@ -182,6 +182,8 @@ type testGraph interface { addRandChannel(*btcec.PublicKey, *btcec.PublicKey, btcutil.Amount) (*ChannelEdge, *ChannelEdge, error) + + addRandNode() (*btcec.PublicKey, error) } func newDiskChanGraph() (testGraph, func(), error) { From b9c33da3f8bdcff091c2d5e34a06ef31ca8d104b Mon Sep 17 00:00:00 2001 From: "Johan T. Halseth" Date: Mon, 10 Dec 2018 14:56:54 +0100 Subject: [PATCH 5/6] autopilot/prefattach: skip nodes having no channels --- autopilot/prefattach.go | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/autopilot/prefattach.go b/autopilot/prefattach.go index 32bd2fcc5..656763072 100644 --- a/autopilot/prefattach.go +++ b/autopilot/prefattach.go @@ -166,6 +166,11 @@ func (p *ConstrainedPrefAttachment) NodeScores(g ChannelGraph, chans []Channel, // skip it for now, which implicitly gives it a score of 0. case len(addrs) == 0: continue + + // If the node had no channels, we skip it, since it would have + // gotten a zero score anyway. + case nodeChans == 0: + continue } // Otherwise we score the node according to its fraction of From 0255db5120f33c013bdaeeb600973280e1e0aaeb Mon Sep 17 00:00:00 2001 From: "Johan T. Halseth" Date: Mon, 10 Dec 2018 14:56:54 +0100 Subject: [PATCH 6/6] autopilot/prefattach_test: ensure non-connected nodes get 0-score This addition to the unit tests makes sure nodes that have no channels in the graph are left out od the scored nodes, implicitly giving them a score of 0. --- autopilot/prefattach_test.go | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/autopilot/prefattach_test.go b/autopilot/prefattach_test.go index 5801c00de..f485ce7d5 100644 --- a/autopilot/prefattach_test.go +++ b/autopilot/prefattach_test.go @@ -376,6 +376,12 @@ func TestConstrainedPrefAttachmentSelectTwoVertexes(t *testing.T) { t1.Fatalf("unable to generate channel: %v", err) } + // We also add a third, non-connected node to the graph. + _, err = graph.addRandNode() + if err != nil { + t1.Fatalf("unable to add random node: %v", err) + } + // Get the score for all nodes found in the graph at // this point. nodes := make(map[NodeID]struct{}) @@ -386,7 +392,7 @@ func TestConstrainedPrefAttachmentSelectTwoVertexes(t *testing.T) { t1.Fatalf("unable to traverse graph: %v", err) } - if len(nodes) != 2 { + if len(nodes) != 3 { t1.Fatalf("expected 2 nodes, found %d", len(nodes)) } @@ -401,8 +407,10 @@ func TestConstrainedPrefAttachmentSelectTwoVertexes(t *testing.T) { "directives: %v", err) } - if len(candidates) != len(nodes) { - t1.Fatalf("all nodes should be scored, "+ + // We expect two candidates, since one of the nodes + // doesn't have any channels. + if len(candidates) != 2 { + t1.Fatalf("2 nodes should be scored, "+ "instead %v were", len(candidates)) }