multi: add new method to generate fresh node announcments

This commit is contained in:
Olaoluwa Osuntokun 2017-08-04 18:32:25 -07:00
parent 6307f7243e
commit 43b736225b
No known key found for this signature in database
GPG Key ID: 9CC5B105D03521A2
7 changed files with 80 additions and 99 deletions

@ -75,7 +75,7 @@ type Config struct {
} }
// New creates a new AuthenticatedGossiper instance, initialized with the // New creates a new AuthenticatedGossiper instance, initialized with the
// passed configuration paramters. // passed configuration parameters.
func New(cfg Config) (*AuthenticatedGossiper, error) { func New(cfg Config) (*AuthenticatedGossiper, error) {
storage, err := channeldb.NewWaitingProofStore(cfg.DB) storage, err := channeldb.NewWaitingProofStore(cfg.DB)
if err != nil { if err != nil {
@ -439,9 +439,9 @@ func (d *AuthenticatedGossiper) processNetworkAnnouncement(nMsg *networkMsg) []l
switch msg := nMsg.msg.(type) { switch msg := nMsg.msg.(type) {
// A new node announcement has arrived which either presents new information // A new node announcement has arrived which either presents new
// about a node in one of the channels we know about, or a updating // information about a node in one of the channels we know about, or a
// previously advertised information. // updating previously advertised information.
case *lnwire.NodeAnnouncement: case *lnwire.NodeAnnouncement:
if nMsg.isRemote { if nMsg.isRemote {
if err := d.validateNodeAnn(msg); err != nil { 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 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) log.Debug(err)
} else { } else {
log.Error(err) log.Error(err)
@ -504,8 +506,8 @@ func (d *AuthenticatedGossiper) processNetworkAnnouncement(nMsg *networkMsg) []l
return nil return nil
} }
// If this is a remote channel annoucement, then we'll validate // If this is a remote channel announcement, then we'll validate
// all the signatues within the proof as it should be well // all the signatures within the proof as it should be well
// formed. // formed.
var proof *channeldb.ChannelAuthProof var proof *channeldb.ChannelAuthProof
if nMsg.isRemote { if nMsg.isRemote {

@ -161,9 +161,9 @@ type fundingConfig struct {
// distinct sub-system? // distinct sub-system?
SignMessage func(pubKey *btcec.PublicKey, msg []byte) (*btcec.Signature, error) SignMessage func(pubKey *btcec.PublicKey, msg []byte) (*btcec.Signature, error)
// SignNodeAnnouncement is used by the fundingManager to sign the // CurrentNodeAnnouncement should return the latest, fully signed node
// updated self node announcements sent after each channel announcement. // announcement from the backing Lighting Network node.
SignNodeAnnouncement func(nodeAnn *lnwire.NodeAnnouncement) (*btcec.Signature, error) CurrentNodeAnnouncement func() (*lnwire.NodeAnnouncement, error)
// SendAnnouncement is used by the FundingManager to announce newly // SendAnnouncement is used by the FundingManager to announce newly
// created channels to the rest of the Lightning Network. // 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, func (f *fundingManager) announceChannel(localIDKey, remoteIDKey, localFundingKey,
remoteFundingKey *btcec.PublicKey, shortChanID lnwire.ShortChannelID, remoteFundingKey *btcec.PublicKey, shortChanID lnwire.ShortChannelID,
chanID lnwire.ChannelID) { 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 { if err != nil {
fndgLog.Errorf("can't generate channel announcement: %v", err) fndgLog.Errorf("can't generate channel announcement: %v", err)
return 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 // TODO(roasbeef): add flag that indicates if should be announced or
// not // not
f.cfg.SendAnnouncement(ann.chanAnn) f.cfg.SendAnnouncement(ann.chanAnn)
f.cfg.SendAnnouncement(ann.chanUpdateAnn) f.cfg.SendAnnouncement(ann.chanUpdateAnn)
f.cfg.SendAnnouncement(ann.chanProof) f.cfg.SendAnnouncement(ann.chanProof)
// Now that the channel is announced to the network, we will also create // Now that the channel is announced to the network, we will also
// and send a node announcement. This is done since a node announcement // obtain and send a node announcement. This is done since a node
// is only accepted after a channel is known for that particular node, // announcement is only accepted after a channel is known for that
// and this might be our first channel. // particular node, and this might be our first channel.
graph := f.cfg.Wallet.Cfg.Database.ChannelGraph() nodeAnn, err := f.cfg.CurrentNodeAnnouncement()
self, err := graph.FetchLightningNode(f.cfg.IDKey)
if err != nil { if err != nil {
fndgLog.Errorf("unable to fetch own lightning node from "+ fndgLog.Errorf("can't generate node announcement: %v", err)
"channel graph: %v", err)
return 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) f.cfg.SendAnnouncement(nodeAnn)
} }

12
lnd.go

@ -20,7 +20,6 @@ import (
flags "github.com/btcsuite/go-flags" flags "github.com/btcsuite/go-flags"
proxy "github.com/grpc-ecosystem/grpc-gateway/runtime" proxy "github.com/grpc-ecosystem/grpc-gateway/runtime"
"github.com/lightningnetwork/lnd/channeldb" "github.com/lightningnetwork/lnd/channeldb"
"github.com/lightningnetwork/lnd/discovery"
"github.com/lightningnetwork/lnd/lnrpc" "github.com/lightningnetwork/lnd/lnrpc"
"github.com/lightningnetwork/lnd/lnwallet" "github.com/lightningnetwork/lnd/lnwallet"
"github.com/lightningnetwork/lnd/lnwire" "github.com/lightningnetwork/lnd/lnwire"
@ -137,15 +136,8 @@ func lndMain() error {
pubKey, msg, pubKey, msg,
) )
}, },
SignNodeAnnouncement: func(nodeAnn *lnwire.NodeAnnouncement) (*btcec.Signature, error) { CurrentNodeAnnouncement: func() (*lnwire.NodeAnnouncement, error) {
sig, err := discovery.SignAnnouncement(nodeSigner, return server.genNodeAnnouncement(true)
server.identityPriv.PubKey(),
nodeAnn,
)
if err != nil {
return nil, err
}
return sig, nil
}, },
SendAnnouncement: func(msg lnwire.Message) error { SendAnnouncement: func(msg lnwire.Message) error {
server.discoverSrv.ProcessLocalAnnouncement(msg, server.discoverSrv.ProcessLocalAnnouncement(msg,

@ -3528,6 +3528,9 @@ type ForceCloseSummary struct {
// SelfOutputSignDesc is a fully populated sign descriptor capable of // SelfOutputSignDesc is a fully populated sign descriptor capable of
// generating a valid signature to sweep the self output. // 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 SelfOutputSignDesc *SignDescriptor
// SelfOutputMaturity is the relative maturity period before the above // SelfOutputMaturity is the relative maturity period before the above

@ -12,7 +12,6 @@ import (
"os" "os"
"path/filepath" "path/filepath"
"strconv" "strconv"
"strings"
"sync" "sync"
"time" "time"
@ -247,14 +246,14 @@ func (l *lightningNode) Start(lndError chan error) error {
return err return err
} }
// Wait until TLS certificate is created before using it, up to 10 sec. // Wait until TLS certificate is created before using it, up to 20 sec.
tlsTimeout := time.After(10 * time.Second) tlsTimeout := time.After(20 * time.Second)
for !fileExists(l.cfg.TLSCertPath) { for !fileExists(l.cfg.TLSCertPath) {
time.Sleep(100 * time.Millisecond) time.Sleep(100 * time.Millisecond)
select { select {
case <-tlsTimeout: case <-tlsTimeout:
panic(fmt.Errorf("timeout waiting for TLS cert file " + panic(fmt.Errorf("timeout waiting for TLS cert file " +
"to be created after 10 seconds")) "to be created after 20 seconds"))
default: default:
} }
} }
@ -395,12 +394,6 @@ type chanWatchRequest struct {
func (l *lightningNode) lightningNetworkWatcher() { func (l *lightningNode) lightningNetworkWatcher() {
defer l.wg.Done() 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) graphUpdates := make(chan *lnrpc.GraphTopologyUpdate)
l.wg.Add(1) l.wg.Add(1)
go func() { go func() {
@ -422,25 +415,7 @@ func (l *lightningNode) lightningNetworkWatcher() {
if err == io.EOF { if err == io.EOF {
return return
} else if err != nil { } else if err != nil {
// If the node has been signalled to quit, then return
// 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))
} }
select { select {

@ -1502,7 +1502,7 @@ func waitForChanToClose(bestHeight uint32, notifier chainntnfs.ChainNotifier,
// The channel has been closed, remove it from any active indexes, and // The channel has been closed, remove it from any active indexes, and
// the database state. // the database state.
srvrLog.Infof("ChannelPoint(%v) is now closed at "+ peerLog.Infof("ChannelPoint(%v) is now closed at "+
"height %v", chanPoint, height.BlockHeight) "height %v", chanPoint, height.BlockHeight)
// Finally, execute the closure call back to mark the confirmation of // Finally, execute the closure call back to mark the confirmation of

@ -94,6 +94,12 @@ type server struct {
// only affect the protocol between these two nodes. // only affect the protocol between these two nodes.
localFeatures *lnwire.FeatureVector 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 wg sync.WaitGroup
quit chan struct{} quit chan struct{}
} }
@ -208,7 +214,7 @@ func newServer(listenAddrs []string, chanDB *channeldb.DB, cc *chainControl,
// TODO(roasbeef): make alias configurable // TODO(roasbeef): make alias configurable
alias := lnwire.NewAlias(hex.EncodeToString(serializedPubKey[:10])) alias := lnwire.NewAlias(hex.EncodeToString(serializedPubKey[:10]))
self := &channeldb.LightningNode{ selfNode := &channeldb.LightningNode{
HaveNodeAnnouncement: true, HaveNodeAnnouncement: true,
LastUpdate: time.Now(), LastUpdate: time.Now(),
Addresses: selfAddrs, 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 // If our information has changed since our last boot, then we'll
// re-sign our node announcement so a fresh authenticated version of it // re-sign our node announcement so a fresh authenticated version of it
// can be propagated throughout the network upon startup. // can be propagated throughout the network upon startup.
//
// TODO(roasbeef): don't always set timestamp above to _now. // TODO(roasbeef): don't always set timestamp above to _now.
self.AuthSig, err = discovery.SignAnnouncement(s.nodeSigner, nodeAnn := &lnwire.NodeAnnouncement{
s.identityPriv.PubKey(), Timestamp: uint32(selfNode.LastUpdate.Unix()),
&lnwire.NodeAnnouncement{ Addresses: selfNode.Addresses,
Timestamp: uint32(self.LastUpdate.Unix()), NodeID: selfNode.PubKey,
Addresses: self.Addresses, Alias: alias,
NodeID: self.PubKey, Features: selfNode.Features,
Alias: alias, }
Features: self.Features, selfNode.AuthSig, err = discovery.SignAnnouncement(s.nodeSigner,
}, s.identityPriv.PubKey(), nodeAnn,
) )
if err != nil { if err != nil {
return nil, fmt.Errorf("unable to generate signature for "+ return nil, fmt.Errorf("unable to generate signature for "+
"self node announcement: %v", err) "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) 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{ s.chanRouter, err = routing.New(routing.Config{
Graph: chanGraph, Graph: chanGraph,
Chain: cc.chainIO, Chain: cc.chainIO,
@ -380,6 +391,26 @@ func (s *server) Stop() error {
return nil 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 // establishPersistentConnections attempts to establish persistent connections
// to all our direct channel collaborators. In order to promote liveness of // to all our direct channel collaborators. In order to promote liveness of
// our active channels, we instruct the connection manager to attempt to // our active channels, we instruct the connection manager to attempt to