From 43b736225b4fc5e51d8c0084503143015d6855ce Mon Sep 17 00:00:00 2001 From: Olaoluwa Osuntokun Date: Fri, 4 Aug 2017 18:32:25 -0700 Subject: [PATCH] multi: add new method to generate fresh node announcments --- discovery/service.go | 16 ++++++------ fundingmanager.go | 60 ++++++++++++++------------------------------ lnd.go | 12 ++------- lnwallet/channel.go | 3 +++ networktest.go | 33 +++--------------------- peer.go | 2 +- server.go | 53 ++++++++++++++++++++++++++++++-------- 7 files changed, 80 insertions(+), 99 deletions(-) diff --git a/discovery/service.go b/discovery/service.go index 590ca5e9..d83d3e9e 100644 --- a/discovery/service.go +++ b/discovery/service.go @@ -75,7 +75,7 @@ type Config struct { } // New creates a new AuthenticatedGossiper instance, initialized with the -// passed configuration paramters. +// passed configuration parameters. func New(cfg Config) (*AuthenticatedGossiper, error) { storage, err := channeldb.NewWaitingProofStore(cfg.DB) if err != nil { @@ -439,9 +439,9 @@ func (d *AuthenticatedGossiper) processNetworkAnnouncement(nMsg *networkMsg) []l switch msg := nMsg.msg.(type) { - // A new node announcement has arrived which either presents new information - // about a node in one of the channels we know about, or a updating - // previously advertised information. + // A new node announcement has arrived which either presents new + // information about a node in one of the channels we know about, or a + // updating previously advertised information. case *lnwire.NodeAnnouncement: if nMsg.isRemote { if err := d.validateNodeAnn(msg); err != nil { @@ -464,7 +464,9 @@ func (d *AuthenticatedGossiper) processNetworkAnnouncement(nMsg *networkMsg) []l } if err := d.cfg.Router.AddNode(node); err != nil { - if routing.IsError(err, routing.ErrOutdated, routing.ErrIgnored) { + if routing.IsError(err, routing.ErrOutdated, + routing.ErrIgnored) { + log.Debug(err) } else { log.Error(err) @@ -504,8 +506,8 @@ func (d *AuthenticatedGossiper) processNetworkAnnouncement(nMsg *networkMsg) []l return nil } - // If this is a remote channel annoucement, then we'll validate - // all the signatues within the proof as it should be well + // If this is a remote channel announcement, then we'll validate + // all the signatures within the proof as it should be well // formed. var proof *channeldb.ChannelAuthProof if nMsg.isRemote { diff --git a/fundingmanager.go b/fundingmanager.go index 4319295d..cfaf7377 100644 --- a/fundingmanager.go +++ b/fundingmanager.go @@ -161,9 +161,9 @@ type fundingConfig struct { // distinct sub-system? SignMessage func(pubKey *btcec.PublicKey, msg []byte) (*btcec.Signature, error) - // SignNodeAnnouncement is used by the fundingManager to sign the - // updated self node announcements sent after each channel announcement. - SignNodeAnnouncement func(nodeAnn *lnwire.NodeAnnouncement) (*btcec.Signature, error) + // CurrentNodeAnnouncement should return the latest, fully signed node + // announcement from the backing Lighting Network node. + CurrentNodeAnnouncement func() (*lnwire.NodeAnnouncement, error) // SendAnnouncement is used by the FundingManager to announce newly // created channels to the rest of the Lightning Network. @@ -1359,58 +1359,36 @@ func (f *fundingManager) newChanAnnouncement(localPubKey, remotePubKey *btcec.Pu func (f *fundingManager) announceChannel(localIDKey, remoteIDKey, localFundingKey, remoteFundingKey *btcec.PublicKey, shortChanID lnwire.ShortChannelID, chanID lnwire.ChannelID) { - ann, err := f.newChanAnnouncement(localIDKey, remoteIDKey, localFundingKey, - remoteFundingKey, shortChanID, chanID) + + // First, we'll create the batch of announcements to be sent upon + // initial channel creation. This includes the channel announcement + // itself, the channel update announcement, and our half of the channel + // proof needed to fully authenticate the channel. + ann, err := f.newChanAnnouncement(localIDKey, remoteIDKey, + localFundingKey, remoteFundingKey, shortChanID, chanID) if err != nil { fndgLog.Errorf("can't generate channel announcement: %v", err) return } + // With the announcements crafted, we'll now send the announcements to + // the rest of the network. + // // TODO(roasbeef): add flag that indicates if should be announced or // not - f.cfg.SendAnnouncement(ann.chanAnn) f.cfg.SendAnnouncement(ann.chanUpdateAnn) f.cfg.SendAnnouncement(ann.chanProof) - // Now that the channel is announced to the network, we will also create - // and send a node announcement. This is done since a node announcement - // is only accepted after a channel is known for that particular node, - // and this might be our first channel. - graph := f.cfg.Wallet.Cfg.Database.ChannelGraph() - self, err := graph.FetchLightningNode(f.cfg.IDKey) + // Now that the channel is announced to the network, we will also + // obtain and send a node announcement. This is done since a node + // announcement is only accepted after a channel is known for that + // particular node, and this might be our first channel. + nodeAnn, err := f.cfg.CurrentNodeAnnouncement() if err != nil { - fndgLog.Errorf("unable to fetch own lightning node from "+ - "channel graph: %v", err) + fndgLog.Errorf("can't generate node announcement: %v", err) return } - - // Create node announcement with updated timestamp to make sure it gets - // propagated in the network, in particular by our local announcement - // process logic. In case we just sent one, add one second to the time, - // to make sure it gets propagated. - timestamp := time.Now().Unix() - if timestamp <= self.LastUpdate.Unix() { - timestamp = self.LastUpdate.Unix() + 1 - } - nodeAnn := &lnwire.NodeAnnouncement{ - Timestamp: uint32(timestamp), - Addresses: self.Addresses, - NodeID: self.PubKey, - Alias: lnwire.NewAlias(self.Alias), - Features: self.Features, - } - - // Since the timestamp is changed, we cannot reuse the old signature - // and must re-sign the announcement. - sign, err := f.cfg.SignNodeAnnouncement(nodeAnn) - if err != nil { - fndgLog.Errorf("unable to generate signature for self node "+ - "announcement: %v", err) - return - } - - nodeAnn.Signature = sign f.cfg.SendAnnouncement(nodeAnn) } diff --git a/lnd.go b/lnd.go index 86dd0336..c48db16a 100644 --- a/lnd.go +++ b/lnd.go @@ -20,7 +20,6 @@ import ( flags "github.com/btcsuite/go-flags" proxy "github.com/grpc-ecosystem/grpc-gateway/runtime" "github.com/lightningnetwork/lnd/channeldb" - "github.com/lightningnetwork/lnd/discovery" "github.com/lightningnetwork/lnd/lnrpc" "github.com/lightningnetwork/lnd/lnwallet" "github.com/lightningnetwork/lnd/lnwire" @@ -137,15 +136,8 @@ func lndMain() error { pubKey, msg, ) }, - SignNodeAnnouncement: func(nodeAnn *lnwire.NodeAnnouncement) (*btcec.Signature, error) { - sig, err := discovery.SignAnnouncement(nodeSigner, - server.identityPriv.PubKey(), - nodeAnn, - ) - if err != nil { - return nil, err - } - return sig, nil + CurrentNodeAnnouncement: func() (*lnwire.NodeAnnouncement, error) { + return server.genNodeAnnouncement(true) }, SendAnnouncement: func(msg lnwire.Message) error { server.discoverSrv.ProcessLocalAnnouncement(msg, diff --git a/lnwallet/channel.go b/lnwallet/channel.go index 4812036a..4dce1ffc 100644 --- a/lnwallet/channel.go +++ b/lnwallet/channel.go @@ -3528,6 +3528,9 @@ type ForceCloseSummary struct { // SelfOutputSignDesc is a fully populated sign descriptor capable of // generating a valid signature to sweep the self output. + // + // NOTE: If the commitment delivery output of the force closing party + // is below the dust limit, then this will be nil. SelfOutputSignDesc *SignDescriptor // SelfOutputMaturity is the relative maturity period before the above diff --git a/networktest.go b/networktest.go index d0faa086..45e59b0e 100644 --- a/networktest.go +++ b/networktest.go @@ -12,7 +12,6 @@ import ( "os" "path/filepath" "strconv" - "strings" "sync" "time" @@ -247,14 +246,14 @@ func (l *lightningNode) Start(lndError chan error) error { return err } - // Wait until TLS certificate is created before using it, up to 10 sec. - tlsTimeout := time.After(10 * time.Second) + // Wait until TLS certificate is created before using it, up to 20 sec. + tlsTimeout := time.After(20 * time.Second) for !fileExists(l.cfg.TLSCertPath) { time.Sleep(100 * time.Millisecond) select { case <-tlsTimeout: panic(fmt.Errorf("timeout waiting for TLS cert file " + - "to be created after 10 seconds")) + "to be created after 20 seconds")) default: } } @@ -395,12 +394,6 @@ type chanWatchRequest struct { func (l *lightningNode) lightningNetworkWatcher() { defer l.wg.Done() - // If the channel router is shutting down, then we won't consider it as - // a real error. This just indicates the daemon itself is quitting. - isShutdownError := func(err error) bool { - return strings.Contains(err.Error(), "shutting down") - } - graphUpdates := make(chan *lnrpc.GraphTopologyUpdate) l.wg.Add(1) go func() { @@ -422,25 +415,7 @@ func (l *lightningNode) lightningNetworkWatcher() { if err == io.EOF { return } else if err != nil { - // If the node has been signalled to quit, then - // we'll exit early. - select { - case <-l.quit: - return - default: - } - - // Otherwise, if the node is shutting down on - // it's own, then we'll also bail out early. - if isShutdownError(err) { - return - } - - // Similar to the case above, we also panic - // here (and end the tests) as these - // notifications are critical to the success of - // many tests. - panic(fmt.Errorf("unable read update ntfn: %v", err)) + return } select { diff --git a/peer.go b/peer.go index e4790f00..5007bb2e 100644 --- a/peer.go +++ b/peer.go @@ -1502,7 +1502,7 @@ func waitForChanToClose(bestHeight uint32, notifier chainntnfs.ChainNotifier, // The channel has been closed, remove it from any active indexes, and // the database state. - srvrLog.Infof("ChannelPoint(%v) is now closed at "+ + peerLog.Infof("ChannelPoint(%v) is now closed at "+ "height %v", chanPoint, height.BlockHeight) // Finally, execute the closure call back to mark the confirmation of diff --git a/server.go b/server.go index b201a7be..f0fccf6f 100644 --- a/server.go +++ b/server.go @@ -94,6 +94,12 @@ type server struct { // only affect the protocol between these two nodes. localFeatures *lnwire.FeatureVector + // currentNodeAnn is the node announcement that has been broadcast to + // the network upon startup, if the attributes of the node (us) has + // changed since last start. + annMtx sync.Mutex + currentNodeAnn *lnwire.NodeAnnouncement + wg sync.WaitGroup quit chan struct{} } @@ -208,7 +214,7 @@ func newServer(listenAddrs []string, chanDB *channeldb.DB, cc *chainControl, // TODO(roasbeef): make alias configurable alias := lnwire.NewAlias(hex.EncodeToString(serializedPubKey[:10])) - self := &channeldb.LightningNode{ + selfNode := &channeldb.LightningNode{ HaveNodeAnnouncement: true, LastUpdate: time.Now(), Addresses: selfAddrs, @@ -220,25 +226,30 @@ func newServer(listenAddrs []string, chanDB *channeldb.DB, cc *chainControl, // 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. - self.AuthSig, err = discovery.SignAnnouncement(s.nodeSigner, - s.identityPriv.PubKey(), - &lnwire.NodeAnnouncement{ - Timestamp: uint32(self.LastUpdate.Unix()), - Addresses: self.Addresses, - NodeID: self.PubKey, - Alias: alias, - Features: self.Features, - }, + nodeAnn := &lnwire.NodeAnnouncement{ + Timestamp: uint32(selfNode.LastUpdate.Unix()), + Addresses: selfNode.Addresses, + NodeID: selfNode.PubKey, + Alias: alias, + Features: selfNode.Features, + } + selfNode.AuthSig, err = discovery.SignAnnouncement(s.nodeSigner, + s.identityPriv.PubKey(), nodeAnn, ) if err != nil { return nil, fmt.Errorf("unable to generate signature for "+ "self node announcement: %v", err) } - if err := chanGraph.SetSourceNode(self); err != nil { + + if err := chanGraph.SetSourceNode(selfNode); err != nil { return nil, fmt.Errorf("can't set self node: %v", err) } + nodeAnn.Signature = selfNode.AuthSig + s.currentNodeAnn = nodeAnn + s.chanRouter, err = routing.New(routing.Config{ Graph: chanGraph, Chain: cc.chainIO, @@ -380,6 +391,26 @@ func (s *server) Stop() error { return nil } +// genNodeAnnouncement generates and returns the current fully signed node +// announcement. If refresh is true, then the time stamp of the announcement +// will be updated in order to ensure it propagates through the network. +func (s *server) genNodeAnnouncement(refresh bool) (*lnwire.NodeAnnouncement, error) { + s.annMtx.Lock() + defer s.annMtx.Unlock() + + if !refresh { + return s.currentNodeAnn, nil + } + + var err error + s.currentNodeAnn.Timestamp = uint32(time.Now().Unix()) + s.currentNodeAnn.Signature, err = discovery.SignAnnouncement(s.nodeSigner, + s.identityPriv.PubKey(), s.currentNodeAnn, + ) + + return s.currentNodeAnn, err +} + // establishPersistentConnections attempts to establish persistent connections // to all our direct channel collaborators. In order to promote liveness of // our active channels, we instruct the connection manager to attempt to