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.
This commit is contained in:
Olaoluwa Osuntokun 2018-08-29 15:44:26 -07:00
parent 73af09a06a
commit a429c56c10
No known key found for this signature in database
GPG Key ID: 964EA263DD637C21
4 changed files with 37 additions and 16 deletions

@ -59,12 +59,12 @@ type dbNode struct {
var _ Node = (*dbNode)(nil) var _ Node = (*dbNode)(nil)
// PubKey is the identity public key of the node. This will be used to attempt // 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. // NOTE: Part of the autopilot.Node interface.
func (d dbNode) PubKey() *btcec.PublicKey { func (d dbNode) PubKey() [33]byte {
pubKey, _ := d.node.PubKey() return d.node.PubKeyBytes
return pubKey
} }
// Addrs returns a slice of publicly reachable public TCP addresses that the // 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. // to target a node for channel opening by the main autopilot agent.
// //
// NOTE: Part of the autopilot.Node interface. // NOTE: Part of the autopilot.Node interface.
func (m memNode) PubKey() *btcec.PublicKey { func (m memNode) PubKey() [33]byte {
return m.pub var n [33]byte
copy(n[:], m.pub.SerializeCompressed())
return n
} }
// Addrs returns a slice of publicly reachable public TCP addresses that the // Addrs returns a slice of publicly reachable public TCP addresses that the

@ -17,8 +17,8 @@ import (
type Node interface { type Node interface {
// PubKey is the identity public key of the node. This will be used to // 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 // attempt to target a node for channel opening by the main autopilot
// agent. // agent. The key will be returned in serialized compressed format.
PubKey() *btcec.PublicKey PubKey() [33]byte
// Addrs returns a slice of publicly reachable public TCP addresses // Addrs returns a slice of publicly reachable public TCP addresses
// that the peer is known to be listening on. // that the peer is known to be listening on.

@ -1,6 +1,7 @@
package autopilot package autopilot
import ( import (
"bytes"
"fmt" "fmt"
prand "math/rand" prand "math/rand"
"time" "time"
@ -153,6 +154,8 @@ func (p *ConstrainedPrefAttachment) Select(self *btcec.PublicKey, g ChannelGraph
return directives, nil return directives, nil
} }
selfPubBytes := self.SerializeCompressed()
// We'll continue our attachment loop until we've exhausted the current // We'll continue our attachment loop until we've exhausted the current
// amount of available funds. // amount of available funds.
visited := make(map[NodeID]struct{}) 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? // TODO(roasbeef): add noise to make adversarially resistant?
if err := g.ForEachNode(func(node Node) error { 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 // Once a node has already been attached to, we'll
// ensure that it isn't factored into any further // 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 // If we come across ourselves, them we'll continue in
// order to avoid attempting to make a channel with // order to avoid attempting to make a channel with
// ourselves. // ourselves.
if node.PubKey().IsEqual(self) { if bytes.Equal(nID[:], selfPubBytes) {
return nil 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 // With the node selected, we'll add this (node, amount) tuple
// to out set of recommended directives. // 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{ directives = append(directives, AttachmentDirective{
// TODO(roasbeef): need curve? // TODO(roasbeef): need curve?
PeerKey: &btcec.PublicKey{ 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 // With the node selected, we'll add it to the set of visited
// nodes to avoid attaching to it again. // nodes to avoid attaching to it again.
visited[NewNodeID(selectedNode.PubKey())] = struct{}{} visited[NodeID(pubBytes)] = struct{}{}
} }
numSelectedNodes := int64(len(directives)) numSelectedNodes := int64(len(directives))

@ -1,6 +1,7 @@
package autopilot package autopilot
import ( import (
"bytes"
"io/ioutil" "io/ioutil"
"os" "os"
"testing" "testing"
@ -344,11 +345,14 @@ func TestConstrainedPrefAttachmentSelectTwoVertexes(t *testing.T) {
// The node attached to should be amongst the two edges // The node attached to should be amongst the two edges
// created above. // created above.
for _, directive := range directives { for _, directive := range directives {
edge1Pub := edge1.Peer.PubKey()
edge2Pub := edge2.Peer.PubKey()
switch { switch {
case directive.PeerKey.IsEqual(edge1.Peer.PubKey()): case bytes.Equal(directive.PeerKey.SerializeCompressed(), edge1Pub[:]):
case directive.PeerKey.IsEqual(edge2.Peer.PubKey()): case bytes.Equal(directive.PeerKey.SerializeCompressed(), edge2Pub[:]):
default: default:
t1.Fatalf("attache to unknown node: %x", t1.Fatalf("attached to unknown node: %x",
directive.PeerKey.SerializeCompressed()) directive.PeerKey.SerializeCompressed())
} }
@ -472,8 +476,15 @@ func TestConstrainedPrefAttachmentSelectGreedyAllocation(t *testing.T) {
if err != nil { if err != nil {
t1.Fatalf("unable to create channel: %v", err) 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( _, _, err = graph.addRandChannel(
edge1.Peer.PubKey(), nil, chanCapacity, peerPub, nil, chanCapacity,
) )
if err != nil { if err != nil {
t1.Fatalf("unable to create channel: %v", err) t1.Fatalf("unable to create channel: %v", err)