fundingmanager: send node announcements after channel open.

Make the fundingmanager send an updated node announcement
each time it opens a new channel. This is to make sure
our node announcement is propagated in the network, since
peers will ignore our node announcements if we haven't
opened any channels yet.
This commit is contained in:
Johan T. Halseth 2017-07-14 21:47:52 +02:00 committed by Olaoluwa Osuntokun
parent 889a4eb48b
commit e2112702e7
3 changed files with 176 additions and 46 deletions

View File

@ -161,6 +161,10 @@ 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
// updated self node announcements sent after each channel announcement.
SignNodeAnnouncement func(nodeAnn *lnwire.NodeAnnouncement) (*btcec.Signature, 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.
SendAnnouncement func(msg lnwire.Message) error SendAnnouncement func(msg lnwire.Message) error
@ -1355,7 +1359,6 @@ 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, ann, err := f.newChanAnnouncement(localIDKey, remoteIDKey, localFundingKey,
remoteFundingKey, shortChanID, chanID) remoteFundingKey, shortChanID, chanID)
if err != nil { if err != nil {
@ -1369,6 +1372,46 @@ func (f *fundingManager) announceChannel(localIDKey, remoteIDKey, localFundingKe
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
// 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)
if err != nil {
fndgLog.Errorf("unable to fetch own lightning node from "+
"channel graph: %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)
} }
// initFundingWorkflow sends a message to the funding manager instructing it // initFundingWorkflow sends a message to the funding manager instructing it

11
lnd.go
View File

@ -18,6 +18,7 @@ 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"
@ -130,6 +131,16 @@ func lndMain() error {
pubKey, msg, 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
},
SendAnnouncement: func(msg lnwire.Message) error { SendAnnouncement: func(msg lnwire.Message) error {
server.discoverSrv.ProcessLocalAnnouncement(msg, server.discoverSrv.ProcessLocalAnnouncement(msg,
idPrivKey.PubKey()) idPrivKey.PubKey())

View File

@ -2241,41 +2241,50 @@ func testGraphTopologyNotifications(net *networkHarness, t *harnessTest) {
} }
}() }()
// The channel opening above should've triggered a new notification // The channel opening above should've triggered a few notifications
// sent to the notification client. // sent to the notification client. We'll expect two channel updates,
const numExpectedUpdates = 2 // and two node announcements.
const numExpectedUpdates = 4
for i := 0; i < numExpectedUpdates; i++ { for i := 0; i < numExpectedUpdates; i++ {
select { select {
// Ensure that a new update for both created edges is properly // Ensure that a new update for both created edges is properly
// dispatched to our registered client. // dispatched to our registered client.
case graphUpdate := <-graphUpdates: case graphUpdate := <-graphUpdates:
if len(graphUpdate.ChannelUpdates) != 1 { if len(graphUpdate.ChannelUpdates) > 0 {
t.Fatalf("expected a single update, instead "+ chanUpdate := graphUpdate.ChannelUpdates[0]
"have %v", len(graphUpdate.ChannelUpdates)) if chanUpdate.Capacity != int64(chanAmt) {
t.Fatalf("channel capacities mismatch:"+
" expected %v, got %v", chanAmt,
btcutil.Amount(chanUpdate.Capacity))
}
switch chanUpdate.AdvertisingNode {
case net.Alice.PubKeyStr:
case net.Bob.PubKeyStr:
default:
t.Fatalf("unknown advertising node: %v",
chanUpdate.AdvertisingNode)
}
switch chanUpdate.ConnectingNode {
case net.Alice.PubKeyStr:
case net.Bob.PubKeyStr:
default:
t.Fatalf("unknown connecting node: %v",
chanUpdate.ConnectingNode)
}
} }
chanUpdate := graphUpdate.ChannelUpdates[0] if len(graphUpdate.NodeUpdates) > 0 {
if chanUpdate.Capacity != int64(chanAmt) { nodeUpdate := graphUpdate.NodeUpdates[0]
t.Fatalf("channel capacities mismatch: expected %v, "+ switch nodeUpdate.IdentityKey {
"got %v", chanAmt, case net.Alice.PubKeyStr:
btcutil.Amount(chanUpdate.Capacity)) case net.Bob.PubKeyStr:
} default:
switch chanUpdate.AdvertisingNode { t.Fatalf("unknown node: %v",
case net.Alice.PubKeyStr: nodeUpdate.IdentityKey)
case net.Bob.PubKeyStr: }
default:
t.Fatalf("unknown advertising node: %v",
chanUpdate.AdvertisingNode)
}
switch chanUpdate.ConnectingNode {
case net.Alice.PubKeyStr:
case net.Bob.PubKeyStr:
default:
t.Fatalf("unknown connecting node: %v",
chanUpdate.ConnectingNode)
} }
case <-time.After(time.Second * 10): case <-time.After(time.Second * 10):
t.Fatalf("notification for new channel not sent") t.Fatalf("timeout waiting for graph notification %v", i)
} }
} }
@ -2319,36 +2328,86 @@ func testGraphTopologyNotifications(net *networkHarness, t *harnessTest) {
} }
// For the final portion of the test, we'll ensure that once a new node // For the final portion of the test, we'll ensure that once a new node
// appears in the network, the proper notification is dispatched. // appears in the network, the proper notification is dispatched. Note
// that a node that does not have any channels open is ignored, so first
// we disconnect Alice and Bob, open a channel between Bob and Carol,
// and finally connect Alice to Bob again.
ctxt, _ = context.WithTimeout(ctxb, timeout)
if err := net.DisconnectNodes(ctxt, net.Alice, net.Bob); err != nil {
t.Fatalf("unable to disconnect alice and bob: %v", err)
}
carol, err := net.NewNode(nil) carol, err := net.NewNode(nil)
if err != nil { if err != nil {
t.Fatalf("unable to create new nodes: %v", err) t.Fatalf("unable to create new nodes: %v", err)
} }
// Connect the new node above to Alice. This should result in the nodes if err := net.ConnectNodes(ctxb, net.Bob, carol); err != nil {
// syncing up their respective graph state, with the new addition being t.Fatalf("unable to connect bob to carol: %v", err)
// the existence of Carol in the graph. }
if err := net.ConnectNodes(ctxb, net.Alice, carol); err != nil { ctxt, _ = context.WithTimeout(ctxb, timeout)
t.Fatalf("unable to connect alice to carol: %v", err) chanPoint = openChannelAndAssert(ctxt, t, net, net.Bob, carol,
chanAmt, 0)
time.Sleep(time.Millisecond * 300)
// Reconnect Alice and Bob. This should result in the nodes syncing up
// their respective graph state, with the new addition being the
// existence of Carol in the graph, and also the channel between Bob
// and Carol. Note that we will also receive a node announcement from
// Bob, since a node will update its node announcement after a new
// channel is opened.
if err := net.ConnectNodes(ctxb, net.Alice, net.Bob); err != nil {
t.Fatalf("unable to connect alice to bob: %v", err)
} }
// We should receive an update advertising the newly connected node. // We should receive an update advertising the newly connected node,
select { // Bob's new node announcement, and the channel between Bob and Carol.
case graphUpdate := <-graphUpdates: for i := 0; i < 4; i++ {
if len(graphUpdate.NodeUpdates) != 1 { select {
t.Fatalf("expected a single update, instead "+ case graphUpdate := <-graphUpdates:
"have %v", len(graphUpdate.NodeUpdates))
}
nodeUpdate := graphUpdate.NodeUpdates[0] if len(graphUpdate.NodeUpdates) > 0 {
if nodeUpdate.IdentityKey != carol.PubKeyStr { nodeUpdate := graphUpdate.NodeUpdates[0]
t.Fatalf("node update pubkey mismatch: expected %v, got %v", switch nodeUpdate.IdentityKey {
carol.PubKeyStr, nodeUpdate.IdentityKey) case carol.PubKeyStr:
case net.Bob.PubKeyStr:
default:
t.Fatalf("unknown node update pubey: %v",
nodeUpdate.IdentityKey)
}
}
if len(graphUpdate.ChannelUpdates) > 0 {
chanUpdate := graphUpdate.ChannelUpdates[0]
if chanUpdate.Capacity != int64(chanAmt) {
t.Fatalf("channel capacities mismatch:"+
" expected %v, got %v", chanAmt,
btcutil.Amount(chanUpdate.Capacity))
}
switch chanUpdate.AdvertisingNode {
case carol.PubKeyStr:
case net.Bob.PubKeyStr:
default:
t.Fatalf("unknown advertising node: %v",
chanUpdate.AdvertisingNode)
}
switch chanUpdate.ConnectingNode {
case carol.PubKeyStr:
case net.Bob.PubKeyStr:
default:
t.Fatalf("unknown connecting node: %v",
chanUpdate.ConnectingNode)
}
}
case <-time.After(time.Second * 10):
t.Fatalf("timeout waiting for graph notification %v", i)
} }
case <-time.After(time.Second * 10):
t.Fatalf("node update ntfn not sent")
} }
// Close the channel between Bob and Carol.
ctxt, _ = context.WithTimeout(context.Background(), timeout)
closeChannelAndAssert(ctxt, t, net, net.Bob, chanPoint, false)
close(quit) close(quit)
// Finally, shutdown carol as our test has concluded successfully. // Finally, shutdown carol as our test has concluded successfully.
@ -2378,6 +2437,20 @@ func testNodeAnnouncement(net *networkHarness, t *harnessTest) {
t.Fatalf("unable to create new nodes: %v", err) t.Fatalf("unable to create new nodes: %v", err)
} }
// We must let Dave have an open channel before he can send a node
// announcement, so we open a channel with Bob,
if err := net.ConnectNodes(ctxb, net.Bob, dave); err != nil {
t.Fatalf("unable to connect bob to carol: %v", err)
}
timeout := time.Duration(time.Second * 5)
ctxt, _ := context.WithTimeout(ctxb, timeout)
chanPoint := openChannelAndAssert(ctxt, t, net, net.Bob, dave,
1000000, 0)
time.Sleep(time.Millisecond * 300)
// When Alice now connects with Dave, Alice will get his node announcement.
if err := net.ConnectNodes(ctxb, net.Alice, dave); err != nil { if err := net.ConnectNodes(ctxb, net.Alice, dave); err != nil {
t.Fatalf("unable to connect bob to carol: %v", err) t.Fatalf("unable to connect bob to carol: %v", err)
} }
@ -2414,6 +2487,9 @@ func testNodeAnnouncement(net *networkHarness, t *harnessTest) {
"graph: %v", ipAddresses) "graph: %v", ipAddresses)
} }
// Close the channel between Bob and Dave.
closeChannelAndAssert(ctxt, t, net, net.Bob, chanPoint, false)
if err := dave.Shutdown(); err != nil { if err := dave.Shutdown(); err != nil {
t.Fatalf("unable to shutdown dave: %v", err) t.Fatalf("unable to shutdown dave: %v", err)
} }