From a429c56c1077beb124dbf09864172b037917a897 Mon Sep 17 00:00:00 2001 From: Olaoluwa Osuntokun Date: Wed, 29 Aug 2018 15:44:26 -0700 Subject: [PATCH 1/2] autopilot: update the Node interface to return a raw bytes, not the key In this commit, we modify the Node interface to return a set of raw bytes, rather than the full pubkey struct. We do this as within the package, commonly we only require the pubkey bytes for fingerprinting purposes. Before this commit, we were forced to _always_ decompress the pubkey which can be expensive done thousands of times a second. --- autopilot/graph.go | 15 +++++++++------ autopilot/interface.go | 4 ++-- autopilot/prefattach.go | 15 +++++++++++---- autopilot/prefattach_test.go | 19 +++++++++++++++---- 4 files changed, 37 insertions(+), 16 deletions(-) diff --git a/autopilot/graph.go b/autopilot/graph.go index 61515a79..7f9cd4d4 100644 --- a/autopilot/graph.go +++ b/autopilot/graph.go @@ -59,12 +59,12 @@ type dbNode struct { var _ Node = (*dbNode)(nil) // PubKey is the identity public key of the node. This will be used to attempt -// to target a node for channel opening by the main autopilot agent. +// to target a node for channel opening by the main autopilot agent. The key +// will be returned in serialized compressed format. // // NOTE: Part of the autopilot.Node interface. -func (d dbNode) PubKey() *btcec.PublicKey { - pubKey, _ := d.node.PubKey() - return pubKey +func (d dbNode) PubKey() [33]byte { + return d.node.PubKeyBytes } // Addrs returns a slice of publicly reachable public TCP addresses that the @@ -406,8 +406,11 @@ var _ Node = (*memNode)(nil) // to target a node for channel opening by the main autopilot agent. // // NOTE: Part of the autopilot.Node interface. -func (m memNode) PubKey() *btcec.PublicKey { - return m.pub +func (m memNode) PubKey() [33]byte { + var n [33]byte + copy(n[:], m.pub.SerializeCompressed()) + + return n } // Addrs returns a slice of publicly reachable public TCP addresses that the diff --git a/autopilot/interface.go b/autopilot/interface.go index 2c7c5191..7f632d89 100644 --- a/autopilot/interface.go +++ b/autopilot/interface.go @@ -17,8 +17,8 @@ import ( type Node interface { // PubKey is the identity public key of the node. This will be used to // attempt to target a node for channel opening by the main autopilot - // agent. - PubKey() *btcec.PublicKey + // agent. The key will be returned in serialized compressed format. + PubKey() [33]byte // Addrs returns a slice of publicly reachable public TCP addresses // that the peer is known to be listening on. diff --git a/autopilot/prefattach.go b/autopilot/prefattach.go index 6dfc82b2..fd1913ed 100644 --- a/autopilot/prefattach.go +++ b/autopilot/prefattach.go @@ -1,6 +1,7 @@ package autopilot import ( + "bytes" "fmt" prand "math/rand" "time" @@ -153,6 +154,8 @@ func (p *ConstrainedPrefAttachment) Select(self *btcec.PublicKey, g ChannelGraph return directives, nil } + selfPubBytes := self.SerializeCompressed() + // We'll continue our attachment loop until we've exhausted the current // amount of available funds. visited := make(map[NodeID]struct{}) @@ -174,7 +177,7 @@ func (p *ConstrainedPrefAttachment) Select(self *btcec.PublicKey, g ChannelGraph // // TODO(roasbeef): add noise to make adversarially resistant? if err := g.ForEachNode(func(node Node) error { - nID := NewNodeID(node.PubKey()) + nID := NodeID(node.PubKey()) // Once a node has already been attached to, we'll // ensure that it isn't factored into any further @@ -186,7 +189,7 @@ func (p *ConstrainedPrefAttachment) Select(self *btcec.PublicKey, g ChannelGraph // If we come across ourselves, them we'll continue in // order to avoid attempting to make a channel with // ourselves. - if node.PubKey().IsEqual(self) { + if bytes.Equal(nID[:], selfPubBytes) { return nil } @@ -235,7 +238,11 @@ func (p *ConstrainedPrefAttachment) Select(self *btcec.PublicKey, g ChannelGraph // With the node selected, we'll add this (node, amount) tuple // to out set of recommended directives. - pub := selectedNode.PubKey() + pubBytes := selectedNode.PubKey() + pub, err := btcec.ParsePubKey(pubBytes[:], btcec.S256()) + if err != nil { + return nil, err + } directives = append(directives, AttachmentDirective{ // TODO(roasbeef): need curve? PeerKey: &btcec.PublicKey{ @@ -247,7 +254,7 @@ func (p *ConstrainedPrefAttachment) Select(self *btcec.PublicKey, g ChannelGraph // With the node selected, we'll add it to the set of visited // nodes to avoid attaching to it again. - visited[NewNodeID(selectedNode.PubKey())] = struct{}{} + visited[NodeID(pubBytes)] = struct{}{} } numSelectedNodes := int64(len(directives)) diff --git a/autopilot/prefattach_test.go b/autopilot/prefattach_test.go index e4a7fcf2..b05bdd52 100644 --- a/autopilot/prefattach_test.go +++ b/autopilot/prefattach_test.go @@ -1,6 +1,7 @@ package autopilot import ( + "bytes" "io/ioutil" "os" "testing" @@ -344,11 +345,14 @@ func TestConstrainedPrefAttachmentSelectTwoVertexes(t *testing.T) { // The node attached to should be amongst the two edges // created above. for _, directive := range directives { + edge1Pub := edge1.Peer.PubKey() + edge2Pub := edge2.Peer.PubKey() + switch { - case directive.PeerKey.IsEqual(edge1.Peer.PubKey()): - case directive.PeerKey.IsEqual(edge2.Peer.PubKey()): + case bytes.Equal(directive.PeerKey.SerializeCompressed(), edge1Pub[:]): + case bytes.Equal(directive.PeerKey.SerializeCompressed(), edge2Pub[:]): default: - t1.Fatalf("attache to unknown node: %x", + t1.Fatalf("attached to unknown node: %x", directive.PeerKey.SerializeCompressed()) } @@ -472,8 +476,15 @@ func TestConstrainedPrefAttachmentSelectGreedyAllocation(t *testing.T) { if err != nil { t1.Fatalf("unable to create channel: %v", err) } + peerPubBytes := edge1.Peer.PubKey() + peerPub, err := btcec.ParsePubKey( + peerPubBytes[:], btcec.S256(), + ) + if err != nil { + t.Fatalf("unable to parse pubkey: %v", err) + } _, _, err = graph.addRandChannel( - edge1.Peer.PubKey(), nil, chanCapacity, + peerPub, nil, chanCapacity, ) if err != nil { t1.Fatalf("unable to create channel: %v", err) From 8f843c5eaaddc78ae2dafd3682fd13e796fe232d Mon Sep 17 00:00:00 2001 From: Olaoluwa Osuntokun Date: Wed, 29 Aug 2018 15:45:33 -0700 Subject: [PATCH 2/2] discovery: update autopilot.Node usage to match recent API changes --- discovery/bootstrapper.go | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/discovery/bootstrapper.go b/discovery/bootstrapper.go index 35782d6d..e53ecfe3 100644 --- a/discovery/bootstrapper.go +++ b/discovery/bootstrapper.go @@ -177,7 +177,7 @@ func (c *ChannelGraphBootstrapper) SampleNodeAddrs(numAddrs uint32, ) err := c.chanGraph.ForEachNode(func(node autopilot.Node) error { - nID := autopilot.NewNodeID(node.PubKey()) + nID := autopilot.NodeID(node.PubKey()) if _, ok := c.tried[nID]; ok { return nil } @@ -187,8 +187,8 @@ func (c *ChannelGraphBootstrapper) SampleNodeAddrs(numAddrs uint32, // value. When comparing, we skip the first byte as // it's 50/50. If it isn't less, than then we'll // continue forward. - nodePub := node.PubKey().SerializeCompressed()[1:] - if bytes.Compare(c.hashAccumulator[:], nodePub) > 0 { + nodePubKeyBytes := node.PubKey() + if bytes.Compare(c.hashAccumulator[:], nodePubKeyBytes[1:]) > 0 { return nil } @@ -205,11 +205,18 @@ func (c *ChannelGraphBootstrapper) SampleNodeAddrs(numAddrs uint32, return nil } + nodePub, err := btcec.ParsePubKey( + nodePubKeyBytes[:], btcec.S256(), + ) + if err != nil { + return err + } + // At this point, we've found an eligible node, // so we'll return early with our shibboleth // error. a = append(a, &lnwire.NetAddress{ - IdentityKey: node.PubKey(), + IdentityKey: nodePub, Address: nodeAddr, }) }