diff --git a/fundingmanager.go b/fundingmanager.go index 0acfadcf..abd7df3f 100644 --- a/fundingmanager.go +++ b/fundingmanager.go @@ -15,9 +15,6 @@ import ( "github.com/coreos/bbolt" "github.com/davecgh/go-spew/spew" "github.com/go-errors/errors" - "golang.org/x/crypto/salsa20" - "google.golang.org/grpc" - "github.com/lightningnetwork/lnd/chainntnfs" "github.com/lightningnetwork/lnd/channeldb" "github.com/lightningnetwork/lnd/htlcswitch" @@ -27,6 +24,8 @@ import ( "github.com/lightningnetwork/lnd/lnwallet" "github.com/lightningnetwork/lnd/lnwire" "github.com/lightningnetwork/lnd/routing" + "golang.org/x/crypto/salsa20" + "google.golang.org/grpc" ) const ( @@ -2149,16 +2148,44 @@ func (f *fundingManager) addToRouterGraph(completeChan *channeldb.OpenChannel, func (f *fundingManager) annAfterSixConfs(completeChan *channeldb.OpenChannel, shortChanID *lnwire.ShortChannelID) error { - // If this channel is meant to be announced to the greater network, - // wait until the funding tx has reached 6 confirmations before - // announcing it. + // If this channel is not meant to be announced to the greater network, + // we'll only send our NodeAnnouncement to our counterparty to ensure we + // don't leak any of our information. announceChan := completeChan.ChannelFlags&lnwire.FFAnnounceChannel != 0 if !announceChan { fndgLog.Debugf("Will not announce private channel %v.", shortChanID.ToUint64()) + + peerChan := make(chan lnpeer.Peer, 1) + f.cfg.NotifyWhenOnline(completeChan.IdentityPub, peerChan) + + var peer lnpeer.Peer + select { + case peer = <-peerChan: + case <-f.quit: + return ErrFundingManagerShuttingDown + } + + nodeAnn, err := f.cfg.CurrentNodeAnnouncement() + if err != nil { + return fmt.Errorf("unable to retrieve current node "+ + "announcement: %v", err) + } + + chanID := lnwire.NewChanIDFromOutPoint( + &completeChan.FundingOutpoint, + ) + pubKey := peer.PubKey() + fndgLog.Debugf("Sending our NodeAnnouncement for "+ + "ChannelID(%v) to %x", chanID, pubKey) + + if err := peer.SendMessage(true, &nodeAnn); err != nil { + return fmt.Errorf("unable to send node announcement "+ + "to peer %x: %v", pubKey, err) + } } else { - // Register with the ChainNotifier for a notification once the - // funding transaction reaches at least 6 confirmations. + // Otherwise, we'll wait until the funding transaction has + // reached 6 confirmations before announcing it. numConfs := uint32(completeChan.NumConfsRequired) if numConfs < 6 { numConfs = 6 @@ -2176,8 +2203,11 @@ func (f *fundingManager) annAfterSixConfs(completeChan *channeldb.OpenChannel, completeChan.FundingOutpoint, err) } + // Register with the ChainNotifier for a notification once the + // funding transaction reaches at least 6 confirmations. confNtfn, err := f.cfg.Notifier.RegisterConfirmationsNtfn( - &txid, fundingScript, numConfs, completeChan.FundingBroadcastHeight, + &txid, fundingScript, numConfs, + completeChan.FundingBroadcastHeight, ) if err != nil { return fmt.Errorf("Unable to register for "+ diff --git a/fundingmanager_test.go b/fundingmanager_test.go index 2cfd8097..969e4efe 100644 --- a/fundingmanager_test.go +++ b/fundingmanager_test.go @@ -1933,7 +1933,7 @@ func TestFundingManagerPrivateChannel(t *testing.T) { bob.mockNotifier.sixConfChannel <- &chainntnfs.TxConfirmation{} // Since this is a private channel, we shouldn't receive the - // announcement signatures or node announcement messages. + // announcement signatures. select { case ann := <-alice.announceChan: t.Fatalf("unexpectedly got channel announcement message: %v", ann) @@ -1948,6 +1948,25 @@ func TestFundingManagerPrivateChannel(t *testing.T) { // Expected } + // We should however receive each side's node announcement. + select { + case msg := <-alice.msgChan: + if _, ok := msg.(*lnwire.NodeAnnouncement); !ok { + t.Fatalf("expected to receive node announcement") + } + case <-time.After(time.Second): + t.Fatalf("expected to receive node announcement") + } + + select { + case msg := <-bob.msgChan: + if _, ok := msg.(*lnwire.NodeAnnouncement); !ok { + t.Fatalf("expected to receive node announcement") + } + case <-time.After(time.Second): + t.Fatalf("expected to receive node announcement") + } + // The internal state-machine should now have deleted the channelStates // from the database, as the channel is announced. assertNoChannelState(t, alice, bob, fundingOutPoint) @@ -2013,19 +2032,48 @@ func TestFundingManagerPrivateRestart(t *testing.T) { // channel. assertHandleFundingLocked(t, alice, bob) - // Restart Alice's fundingManager so we can prove that the public - // channel announcements are not sent upon restart and that the private - // setting persists upon restart. - recreateAliceFundingManager(t, alice) - time.Sleep(300 * time.Millisecond) - // Notify that six confirmations has been reached on funding transaction. alice.mockNotifier.sixConfChannel <- &chainntnfs.TxConfirmation{} bob.mockNotifier.sixConfChannel <- &chainntnfs.TxConfirmation{} // Since this is a private channel, we shouldn't receive the public - // channel announcement messages announcement signatures or - // node announcement. + // channel announcement messages. + select { + case ann := <-alice.announceChan: + t.Fatalf("unexpectedly got channel announcement message: %v", ann) + case <-time.After(300 * time.Millisecond): + } + + select { + case ann := <-bob.announceChan: + t.Fatalf("unexpectedly got channel announcement message: %v", ann) + case <-time.After(300 * time.Millisecond): + } + + // We should however receive each side's node announcement. + select { + case msg := <-alice.msgChan: + if _, ok := msg.(*lnwire.NodeAnnouncement); !ok { + t.Fatalf("expected to receive node announcement") + } + case <-time.After(time.Second): + t.Fatalf("expected to receive node announcement") + } + + select { + case msg := <-bob.msgChan: + if _, ok := msg.(*lnwire.NodeAnnouncement); !ok { + t.Fatalf("expected to receive node announcement") + } + case <-time.After(time.Second): + t.Fatalf("expected to receive node announcement") + } + + // Restart Alice's fundingManager so we can prove that the public + // channel announcements are not sent upon restart and that the private + // setting persists upon restart. + recreateAliceFundingManager(t, alice) + select { case ann := <-alice.announceChan: t.Fatalf("unexpectedly got channel announcement message: %v", ann)