From 28cf413055afb6975aae59556ad27dad90cf719f Mon Sep 17 00:00:00 2001 From: Wilmer Paulino Date: Mon, 23 Apr 2018 15:55:25 -0400 Subject: [PATCH 1/7] channeldb: add method to retrieve a node's node announcement --- channeldb/graph.go | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/channeldb/graph.go b/channeldb/graph.go index 14968e46e..eb681395e 100644 --- a/channeldb/graph.go +++ b/channeldb/graph.go @@ -1767,6 +1767,43 @@ func (l *LightningNode) AddPubKey(key *btcec.PublicKey) { copy(l.PubKeyBytes[:], key.SerializeCompressed()) } +// NodeAnnouncement retrieves the latest node announcement of the node. +func (l *LightningNode) NodeAnnouncement(signed bool) (*lnwire.NodeAnnouncement, + error) { + + if !l.HaveNodeAnnouncement { + return nil, fmt.Errorf("node does not have node announcement") + } + + alias, err := lnwire.NewNodeAlias(l.Alias) + if err != nil { + return nil, err + } + + nodeAnn := &lnwire.NodeAnnouncement{ + Features: l.Features.RawFeatureVector, + NodeID: l.PubKeyBytes, + RGBColor: l.Color, + Alias: alias, + Addresses: l.Addresses, + Timestamp: uint32(l.LastUpdate.Unix()), + ExtraOpaqueData: l.ExtraOpaqueData, + } + + if !signed { + return nodeAnn, nil + } + + sig, err := lnwire.NewSigFromRawSignature(l.AuthSigBytes) + if err != nil { + return nil, err + } + + nodeAnn.Signature = sig + + return nodeAnn, nil +} + // FetchLightningNode attempts to look up a target node by its identity public // key. If the node isn't found in the database, then ErrGraphNodeNotFound is // returned. From 2dcbdf2622c1db31d1dbf2fa7a448dc14c02259f Mon Sep 17 00:00:00 2001 From: Olaoluwa Osuntokun Date: Thu, 20 Sep 2018 19:20:01 -0700 Subject: [PATCH 2/7] lnwallet: fix logging error when fee is too low in BtcdFeeEstimator --- lnwallet/fee_estimator.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lnwallet/fee_estimator.go b/lnwallet/fee_estimator.go index 24adee934..1f63a19ff 100644 --- a/lnwallet/fee_estimator.go +++ b/lnwallet/fee_estimator.go @@ -229,7 +229,8 @@ func (b *BtcdFeeEstimator) fetchEstimate(confTarget uint32) (SatPerKWeight, erro // Finally, we'll enforce our fee floor. if satPerKw < b.minFeePerKW { walletLog.Debugf("Estimated fee rate of %v sat/kw is too low, "+ - "using fee floor of %v sat/kw instead", b.minFeePerKW) + "using fee floor of %v sat/kw instead", satPerKw, + b.minFeePerKW) satPerKw = b.minFeePerKW } From eaa613f4f55b34344399088f528e3253a9481644 Mon Sep 17 00:00:00 2001 From: Olaoluwa Osuntokun Date: Thu, 20 Sep 2018 19:22:20 -0700 Subject: [PATCH 3/7] discovery+chan_series: replace usage of makeNodeAnn w/ new NodeAnnouncement method --- chan_series.go | 25 +++---------------------- discovery/gossiper.go | 25 ++----------------------- 2 files changed, 5 insertions(+), 45 deletions(-) diff --git a/chan_series.go b/chan_series.go index 27a1c3e64..83b05b028 100644 --- a/chan_series.go +++ b/chan_series.go @@ -89,7 +89,7 @@ func (c *chanSeries) UpdatesInHorizon(chain chainhash.Hash, return nil, err } for _, nodeAnn := range nodeAnnsInHorizon { - nodeUpdate, err := makeNodeAnn(&nodeAnn) + nodeUpdate, err := nodeAnn.NodeAnnouncement(true) if err != nil { return nil, err } @@ -151,25 +151,6 @@ func (c *chanSeries) FilterChannelRange(chain chainhash.Hash, return chanResp, nil } -func makeNodeAnn(n *channeldb.LightningNode) (*lnwire.NodeAnnouncement, error) { - alias, _ := lnwire.NewNodeAlias(n.Alias) - - wireSig, err := lnwire.NewSigFromRawSignature(n.AuthSigBytes) - if err != nil { - return nil, err - } - return &lnwire.NodeAnnouncement{ - Signature: wireSig, - Timestamp: uint32(n.LastUpdate.Unix()), - Addresses: n.Addresses, - NodeID: n.PubKeyBytes, - Features: n.Features.RawFeatureVector, - RGBColor: n.Color, - Alias: alias, - ExtraOpaqueData: n.ExtraOpaqueData, - }, nil -} - // FetchChanAnns returns a full set of channel announcements as well as their // updates that match the set of specified short channel ID's. We'll use this // to reply to a QueryShortChanIDs message sent by a remote peer. The response @@ -221,7 +202,7 @@ func (c *chanSeries) FetchChanAnns(chain chainhash.Hash, nodePub := channel.Policy1.Node.PubKeyBytes hasNodeAnn := channel.Policy1.Node.HaveNodeAnnouncement if _, ok := nodePubsSent[nodePub]; !ok && hasNodeAnn { - nodeAnn, err := makeNodeAnn(channel.Policy1.Node) + nodeAnn, err := channel.Policy1.Node.NodeAnnouncement(true) if err != nil { return nil, err } @@ -238,7 +219,7 @@ func (c *chanSeries) FetchChanAnns(chain chainhash.Hash, nodePub := channel.Policy2.Node.PubKeyBytes hasNodeAnn := channel.Policy2.Node.HaveNodeAnnouncement if _, ok := nodePubsSent[nodePub]; !ok && hasNodeAnn { - nodeAnn, err := makeNodeAnn(channel.Policy2.Node) + nodeAnn, err := channel.Policy2.Node.NodeAnnouncement(true) if err != nil { return nil, err } diff --git a/discovery/gossiper.go b/discovery/gossiper.go index fb66c1325..db3bf9a13 100644 --- a/discovery/gossiper.go +++ b/discovery/gossiper.go @@ -270,27 +270,6 @@ func (d *AuthenticatedGossiper) SynchronizeNode(syncPeer lnpeer.Peer) error { // containing all the messages to be sent to the target peer. var announceMessages []lnwire.Message - makeNodeAnn := func(n *channeldb.LightningNode) ( - *lnwire.NodeAnnouncement, error) { - - alias, _ := lnwire.NewNodeAlias(n.Alias) - - wireSig, err := lnwire.NewSigFromRawSignature(n.AuthSigBytes) - if err != nil { - return nil, err - } - return &lnwire.NodeAnnouncement{ - Signature: wireSig, - Timestamp: uint32(n.LastUpdate.Unix()), - Addresses: n.Addresses, - NodeID: n.PubKeyBytes, - Features: n.Features.RawFeatureVector, - RGBColor: n.Color, - Alias: alias, - ExtraOpaqueData: n.ExtraOpaqueData, - }, nil - } - // We'll use this map to ensure we don't send the same node // announcement more than one time as one node may have many channel // anns we'll need to send. @@ -330,7 +309,7 @@ func (d *AuthenticatedGossiper) SynchronizeNode(syncPeer lnpeer.Peer) error { nodePub := e1.Node.PubKeyBytes hasNodeAnn := e1.Node.HaveNodeAnnouncement if _, ok := nodePubsSent[nodePub]; !ok && hasNodeAnn { - nodeAnn, err := makeNodeAnn(e1.Node) + nodeAnn, err := e1.Node.NodeAnnouncement(true) if err != nil { return err } @@ -352,7 +331,7 @@ func (d *AuthenticatedGossiper) SynchronizeNode(syncPeer lnpeer.Peer) error { nodePub := e2.Node.PubKeyBytes hasNodeAnn := e2.Node.HaveNodeAnnouncement if _, ok := nodePubsSent[nodePub]; !ok && hasNodeAnn { - nodeAnn, err := makeNodeAnn(e2.Node) + nodeAnn, err := e2.Node.NodeAnnouncement(true) if err != nil { return err } From 338946eda4c837e63e3a727ccf075f0431dad97a Mon Sep 17 00:00:00 2001 From: Olaoluwa Osuntokun Date: Thu, 20 Sep 2018 19:25:28 -0700 Subject: [PATCH 4/7] server: update genNodeAnnouncement to also write new node ann to disk In this commit, we update the genNodeAnnouncement method to also write an updated version of the node announcment to disk. Before this commit, we would update the in memory version, but then never write the new version to disk. As a result, when connecting to new peers, we would never propagate the new version of this announcement to the network. --- server.go | 31 +++++++++++++++++++++++++++++-- 1 file changed, 29 insertions(+), 2 deletions(-) diff --git a/server.go b/server.go index 5385b2456..d4714ce9c 100644 --- a/server.go +++ b/server.go @@ -1526,32 +1526,59 @@ func (s *server) genNodeAnnouncement(refresh bool, s.mu.Lock() defer s.mu.Unlock() + // If we don't need to refresh the announcement, then we can return a + // copy of our cached version. if !refresh { return *s.currentNodeAnn, nil } + // Now that we know we need to update our copy, we'll apply all the + // function updates that'll mutate the current version of our node + // announcement. for _, update := range updates { update(s.currentNodeAnn) } + // We'll now update the timestamp, ensuring that with each update, the + // timestamp monotonically increases. newStamp := uint32(time.Now().Unix()) if newStamp <= s.currentNodeAnn.Timestamp { newStamp = s.currentNodeAnn.Timestamp + 1 } - s.currentNodeAnn.Timestamp = newStamp + + // Now that the announce tn is fully updated, we'll generate a new + // signature over the announcement to ensure nodes on the network + // accepted the new authenticated announcement. sig, err := discovery.SignAnnouncement( s.nodeSigner, s.identityPriv.PubKey(), s.currentNodeAnn, ) if err != nil { return lnwire.NodeAnnouncement{}, err } - s.currentNodeAnn.Signature, err = lnwire.NewSigFromSignature(sig) if err != nil { return lnwire.NodeAnnouncement{}, err } + // Finally, we'll update the on-disk version of our announcement so it + // will eventually propagate to nodes in the network. + selfNode := &channeldb.LightningNode{ + HaveNodeAnnouncement: true, + LastUpdate: time.Unix(int64(s.currentNodeAnn.Timestamp), 0), + Addresses: s.currentNodeAnn.Addresses, + Alias: s.currentNodeAnn.Alias.String(), + Features: lnwire.NewFeatureVector( + s.currentNodeAnn.Features, lnwire.GlobalFeatures, + ), + Color: s.currentNodeAnn.RGBColor, + AuthSigBytes: sig.Serialize(), + } + if err := s.chanDB.ChannelGraph().SetSourceNode(selfNode); err != nil { + return *s.currentNodeAnn, fmt.Errorf("can't set self node: %v", + err) + } + return *s.currentNodeAnn, nil } From e36000545292ab44a527214699fa7220311d213c Mon Sep 17 00:00:00 2001 From: Olaoluwa Osuntokun Date: Thu, 20 Sep 2018 19:27:12 -0700 Subject: [PATCH 5/7] server: ensure we update our node ann with new tor addrs in initTorController Fixes #1939. --- server.go | 65 ++++++++++++++++++++++++++++--------------------------- 1 file changed, 33 insertions(+), 32 deletions(-) diff --git a/server.go b/server.go index d4714ce9c..237813942 100644 --- a/server.go +++ b/server.go @@ -466,18 +466,12 @@ func newServer(listenAddrs []net.Addr, chanDB *channeldb.DB, cc *chainControl, } copy(selfNode.PubKeyBytes[:], privKey.PubKey().SerializeCompressed()) - // If our information has changed since our last boot, then we'll - // re-sign our node announcement so a fresh authenticated version of it - // can be propagated throughout the network upon startup. - // - // TODO(roasbeef): don't always set timestamp above to _now. - nodeAnn := &lnwire.NodeAnnouncement{ - Timestamp: uint32(selfNode.LastUpdate.Unix()), - Addresses: selfNode.Addresses, - NodeID: selfNode.PubKeyBytes, - Alias: nodeAlias, - Features: selfNode.Features.RawFeatureVector, - RGBColor: color, + // Based on the disk representation of the node announcement generated + // above, we'll generate a node announcement that can go out on the + // network so we can properly sign it. + nodeAnn, err := selfNode.NodeAnnouncement(false) + if err != nil { + return nil, fmt.Errorf("unable to gen self node ann: %v", err) } authSig, err := discovery.SignAnnouncement( s.nodeSigner, s.identityPriv.PubKey(), nodeAnn, @@ -1512,7 +1506,32 @@ func (s *server) initTorController() error { // Now that the onion service has been created, we'll add the onion // address it can be reached at to our list of advertised addresses. - s.currentNodeAnn.Addresses = append(s.currentNodeAnn.Addresses, addr) + newNodeAnn, err := s.genNodeAnnouncement( + true, func(currentAnn *lnwire.NodeAnnouncement) { + currentAnn.Addresses = append(currentAnn.Addresses, addr) + }, + ) + if err != nil { + return fmt.Errorf("Unable to generate new node "+ + "announcement: %v", err) + } + + // Finally, we'll update the on-disk version of our announcement so it + // will eventually propagate to nodes in the network. + selfNode := &channeldb.LightningNode{ + HaveNodeAnnouncement: true, + LastUpdate: time.Unix(int64(newNodeAnn.Timestamp), 0), + Addresses: newNodeAnn.Addresses, + Alias: newNodeAnn.Alias.String(), + Features: lnwire.NewFeatureVector( + newNodeAnn.Features, lnwire.GlobalFeatures, + ), + Color: newNodeAnn.RGBColor, + AuthSigBytes: newNodeAnn.Signature.ToSignatureBytes(), + } + if err := s.chanDB.ChannelGraph().SetSourceNode(selfNode); err != nil { + return fmt.Errorf("can't set self node: %v", err) + } return nil } @@ -1547,7 +1566,7 @@ func (s *server) genNodeAnnouncement(refresh bool, } s.currentNodeAnn.Timestamp = newStamp - // Now that the announce tn is fully updated, we'll generate a new + // Now that the annoncement is fully updated, we'll generate a new // signature over the announcement to ensure nodes on the network // accepted the new authenticated announcement. sig, err := discovery.SignAnnouncement( @@ -1561,24 +1580,6 @@ func (s *server) genNodeAnnouncement(refresh bool, return lnwire.NodeAnnouncement{}, err } - // Finally, we'll update the on-disk version of our announcement so it - // will eventually propagate to nodes in the network. - selfNode := &channeldb.LightningNode{ - HaveNodeAnnouncement: true, - LastUpdate: time.Unix(int64(s.currentNodeAnn.Timestamp), 0), - Addresses: s.currentNodeAnn.Addresses, - Alias: s.currentNodeAnn.Alias.String(), - Features: lnwire.NewFeatureVector( - s.currentNodeAnn.Features, lnwire.GlobalFeatures, - ), - Color: s.currentNodeAnn.RGBColor, - AuthSigBytes: sig.Serialize(), - } - if err := s.chanDB.ChannelGraph().SetSourceNode(selfNode); err != nil { - return *s.currentNodeAnn, fmt.Errorf("can't set self node: %v", - err) - } - return *s.currentNodeAnn, nil } From 0879a7354fa236dd2f6dfaf7f54955f2270cc787 Mon Sep 17 00:00:00 2001 From: Olaoluwa Osuntokun Date: Thu, 20 Sep 2018 19:28:11 -0700 Subject: [PATCH 6/7] server: re-work initial node ann creation to use LightnignNode.NodeAnnouncement --- server.go | 33 ++++++++++++++++++++++----------- 1 file changed, 22 insertions(+), 11 deletions(-) diff --git a/server.go b/server.go index 237813942..4a885b7dc 100644 --- a/server.go +++ b/server.go @@ -440,14 +440,19 @@ func newServer(listenAddrs []net.Addr, chanDB *channeldb.DB, cc *chainControl, chanGraph := chanDB.ChannelGraph() - // Parse node color from configuration. + // We'll now reconstruct a node announcement based on our current + // configuration so we can send it out as a sort of heart beat within + // the network. + // + // We'll start by parsing the node color from configuration. color, err := parseHexColor(cfg.Color) if err != nil { srvrLog.Errorf("unable to parse color: %v\n", err) return nil, err } - // If no alias is provided, default to first 10 characters of public key + // If no alias is provided, default to first 10 characters of public + // key. alias := cfg.Alias if alias == "" { alias = hex.EncodeToString(serializedPubKey[:10]) @@ -473,6 +478,9 @@ func newServer(listenAddrs []net.Addr, chanDB *channeldb.DB, cc *chainControl, if err != nil { return nil, fmt.Errorf("unable to gen self node ann: %v", err) } + + // With the announcement generated, we'll sign it to properly + // authenticate the message on the network. authSig, err := discovery.SignAnnouncement( s.nodeSigner, s.identityPriv.PubKey(), nodeAnn, ) @@ -480,18 +488,21 @@ func newServer(listenAddrs []net.Addr, chanDB *channeldb.DB, cc *chainControl, return nil, fmt.Errorf("unable to generate signature for "+ "self node announcement: %v", err) } - selfNode.AuthSigBytes = authSig.Serialize() - s.currentNodeAnn = nodeAnn - - if err := chanGraph.SetSourceNode(selfNode); err != nil { - return nil, fmt.Errorf("can't set self node: %v", err) - } - - nodeAnn.Signature, err = lnwire.NewSigFromRawSignature(selfNode.AuthSigBytes) + nodeAnn.Signature, err = lnwire.NewSigFromRawSignature( + selfNode.AuthSigBytes, + ) if err != nil { return nil, err } + + // Finally, we'll update the representation on disk, and update our + // cached in-memory version as well. + if err := chanGraph.SetSourceNode(selfNode); err != nil { + return nil, fmt.Errorf("can't set self node: %v", err) + } + s.currentNodeAnn = nodeAnn + s.chanRouter, err = routing.New(routing.Config{ Graph: chanGraph, Chain: cc.chainIO, @@ -1566,7 +1577,7 @@ func (s *server) genNodeAnnouncement(refresh bool, } s.currentNodeAnn.Timestamp = newStamp - // Now that the annoncement is fully updated, we'll generate a new + // Now that the announcement is fully updated, we'll generate a new // signature over the announcement to ensure nodes on the network // accepted the new authenticated announcement. sig, err := discovery.SignAnnouncement( From 7166130037b33cd9ca83a369578f988a747b423b Mon Sep 17 00:00:00 2001 From: Wilmer Paulino Date: Thu, 20 Sep 2018 19:23:34 -0700 Subject: [PATCH 7/7] lnd_test: add onion addresses to testNodeAnnouncement In this commit, we include onion addresses in testNodeAnnouncement to ensure they properly propagate throughout the network. --- lnd_test.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lnd_test.go b/lnd_test.go index 57fc0f349..9a72e994c 100644 --- a/lnd_test.go +++ b/lnd_test.go @@ -7858,6 +7858,8 @@ func testNodeAnnouncement(net *lntest.NetworkHarness, t *harnessTest) { advertisedAddrs := []string{ "192.168.1.1:8333", "[2001:db8:85a3:8d3:1319:8a2e:370:7348]:8337", + "bkb6azqggsaiskzi.onion:9735", + "fomvuglh6h6vcag73xo5t5gv56ombih3zr2xvplkpbfd7wrog4swjwid.onion:1234", } var lndArgs []string