diff --git a/lnwire/node_announcement.go b/lnwire/node_announcement.go index 4ea64fa6..f0d897bc 100644 --- a/lnwire/node_announcement.go +++ b/lnwire/node_announcement.go @@ -101,14 +101,6 @@ type NodeAnnouncement struct { ExtraOpaqueData []byte } -// UpdateNodeAnnAddrs is a functional option that allows updating the addresses -// of the given node announcement. -func UpdateNodeAnnAddrs(addrs []net.Addr) func(*NodeAnnouncement) { - return func(nodeAnn *NodeAnnouncement) { - nodeAnn.Addresses = addrs - } -} - // A compile time check to ensure NodeAnnouncement implements the // lnwire.Message interface. var _ Message = (*NodeAnnouncement)(nil) diff --git a/netann/node_announcement.go b/netann/node_announcement.go new file mode 100644 index 00000000..84a26105 --- /dev/null +++ b/netann/node_announcement.go @@ -0,0 +1,60 @@ +package netann + +import ( + "net" + "time" + + "github.com/btcsuite/btcd/btcec" + "github.com/lightningnetwork/lnd/lnwallet" + "github.com/lightningnetwork/lnd/lnwire" +) + +// NodeAnnModifier is a closure that makes in-place modifications to an +// lnwire.NodeAnnouncement. +type NodeAnnModifier func(*lnwire.NodeAnnouncement) + +// NodeAnnSetAddrs is a functional option that allows updating the addresses of +// the given node announcement. +func NodeAnnSetAddrs(addrs []net.Addr) func(*lnwire.NodeAnnouncement) { + return func(nodeAnn *lnwire.NodeAnnouncement) { + nodeAnn.Addresses = addrs + } +} + +// NodeAnnSetTimestamp is a functional option that sets the timestamp of the +// announcement to the current time, or increments it if the timestamp is +// already in the future. +func NodeAnnSetTimestamp(nodeAnn *lnwire.NodeAnnouncement) { + newTimestamp := uint32(time.Now().Unix()) + if newTimestamp <= nodeAnn.Timestamp { + // Increment the prior value to ensure the timestamp + // monotonically increases, otherwise the announcement won't + // propagate. + newTimestamp = nodeAnn.Timestamp + 1 + } + nodeAnn.Timestamp = newTimestamp +} + +// SignNodeAnnouncement applies the given modifies to the passed +// lnwire.NodeAnnouncement, then signs the resulting announcement. The provided +// update should be the most recent, valid update, otherwise the timestamp may +// not monotonically increase from the prior. +func SignNodeAnnouncement(signer lnwallet.MessageSigner, + pubKey *btcec.PublicKey, nodeAnn *lnwire.NodeAnnouncement, + mods ...NodeAnnModifier) error { + + // Apply the requested changes to the node announcement. + for _, modifier := range mods { + modifier(nodeAnn) + } + + // Create the DER-encoded ECDSA signature over the message digest. + sig, err := SignAnnouncement(signer, pubKey, nodeAnn) + if err != nil { + return err + } + + // Parse the DER-encoded signature into a fixed-size 64-byte array. + nodeAnn.Signature, err = lnwire.NewSigFromSignature(sig) + return err +} diff --git a/server.go b/server.go index 32caa33e..db9ba4e9 100644 --- a/server.go +++ b/server.go @@ -1657,7 +1657,7 @@ out: // announcement with the updated addresses and broadcast // it to our peers. newNodeAnn, err := s.genNodeAnnouncement( - true, lnwire.UpdateNodeAnnAddrs(newAddrs), + true, netann.NodeAnnSetAddrs(newAddrs), ) if err != nil { srvrLog.Debugf("Unable to generate new node "+ @@ -2039,7 +2039,7 @@ func (s *server) initTorController() error { // 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, - updates ...func(*lnwire.NodeAnnouncement)) (lnwire.NodeAnnouncement, error) { + modifiers ...netann.NodeAnnModifier) (lnwire.NodeAnnouncement, error) { s.mu.Lock() defer s.mu.Unlock() @@ -2050,34 +2050,19 @@ func (s *server) genNodeAnnouncement(refresh bool, 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) - } + // Always update the timestamp when refreshing to ensure the update + // propagates. + modifiers = append(modifiers, netann.NodeAnnSetTimestamp) - // 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 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 := netann.SignAnnouncement( + // Otherwise, we'll sign a new update after applying all of the passed + // modifiers. + err := netann.SignNodeAnnouncement( s.nodeSigner, s.identityPriv.PubKey(), s.currentNodeAnn, + modifiers..., ) if err != nil { return lnwire.NodeAnnouncement{}, err } - s.currentNodeAnn.Signature, err = lnwire.NewSigFromSignature(sig) - if err != nil { - return lnwire.NodeAnnouncement{}, err - } return *s.currentNodeAnn, nil }