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

View File

@ -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 {

View File

@ -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)
}

12
lnd.go
View File

@ -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,

View File

@ -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

View File

@ -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 {

View File

@ -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

View File

@ -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