diff --git a/netann/chan_status_manager.go b/netann/chan_status_manager.go index c1eedc7753..fea7c5927c 100644 --- a/netann/chan_status_manager.go +++ b/netann/chan_status_manager.go @@ -60,7 +60,8 @@ type ChanStatusConfig struct { // ApplyChannelUpdate processes new ChannelUpdates signed by our node by // updating our local routing table and broadcasting the update to our // peers. - ApplyChannelUpdate func(*lnwire.ChannelUpdate) error + ApplyChannelUpdate func(*lnwire.ChannelUpdate, *wire.OutPoint, + bool) error // DB stores the set of channels that are to be monitored. DB DB @@ -621,7 +622,7 @@ func (m *ChanStatusManager) signAndSendNextUpdate(outpoint wire.OutPoint, // Retrieve the latest update for this channel. We'll use this // as our starting point to send the new update. - chanUpdate, err := m.fetchLastChanUpdateByOutPoint(outpoint) + chanUpdate, private, err := m.fetchLastChanUpdateByOutPoint(outpoint) if err != nil { return err } @@ -634,22 +635,26 @@ func (m *ChanStatusManager) signAndSendNextUpdate(outpoint wire.OutPoint, return err } - return m.cfg.ApplyChannelUpdate(chanUpdate) + return m.cfg.ApplyChannelUpdate(chanUpdate, &outpoint, private) } // fetchLastChanUpdateByOutPoint fetches the latest policy for our direction of // a channel, and crafts a new ChannelUpdate with this policy. Returns an error -// in case our ChannelEdgePolicy is not found in the database. +// in case our ChannelEdgePolicy is not found in the database. Also returns if +// the channel is private by checking AuthProof for nil. func (m *ChanStatusManager) fetchLastChanUpdateByOutPoint(op wire.OutPoint) ( - *lnwire.ChannelUpdate, error) { + *lnwire.ChannelUpdate, bool, error) { // Get the edge info and policies for this channel from the graph. info, edge1, edge2, err := m.cfg.Graph.FetchChannelEdgesByOutpoint(&op) if err != nil { - return nil, err + return nil, false, err } - return ExtractChannelUpdate(m.ourPubKeyBytes, info, edge1, edge2) + update, err := ExtractChannelUpdate( + m.ourPubKeyBytes, info, edge1, edge2, + ) + return update, info.AuthProof == nil, err } // loadInitialChanState determines the initial ChannelState for a particular @@ -660,7 +665,7 @@ func (m *ChanStatusManager) fetchLastChanUpdateByOutPoint(op wire.OutPoint) ( func (m *ChanStatusManager) loadInitialChanState( outpoint *wire.OutPoint) (ChannelState, error) { - lastUpdate, err := m.fetchLastChanUpdateByOutPoint(*outpoint) + lastUpdate, _, err := m.fetchLastChanUpdateByOutPoint(*outpoint) if err != nil { return ChannelState{}, err } diff --git a/netann/chan_status_manager_test.go b/netann/chan_status_manager_test.go index 14096d086b..e068184f89 100644 --- a/netann/chan_status_manager_test.go +++ b/netann/chan_status_manager_test.go @@ -176,7 +176,9 @@ func (g *mockGraph) FetchChannelEdgesByOutpoint( return info, pol1, pol2, nil } -func (g *mockGraph) ApplyChannelUpdate(update *lnwire.ChannelUpdate) error { +func (g *mockGraph) ApplyChannelUpdate(update *lnwire.ChannelUpdate, + op *wire.OutPoint, private bool) error { + g.mu.Lock() defer g.mu.Unlock() diff --git a/peer/brontide.go b/peer/brontide.go index acedfe3b20..83ee6f39c1 100644 --- a/peer/brontide.go +++ b/peer/brontide.go @@ -330,6 +330,18 @@ type Config struct { // from the peer. HandleCustomMessage func(peer [33]byte, msg *lnwire.Custom) error + // GetAliases is passed to created links so the Switch and link can be + // aware of the channel's aliases. + GetAliases func(base lnwire.ShortChannelID) []lnwire.ShortChannelID + + // RequestAlias allows the Brontide struct to request an alias to send + // to the peer. + RequestAlias func() (lnwire.ShortChannelID, error) + + // AddLocalAlias persists an alias to an underlying alias store. + AddLocalAlias func(alias, base lnwire.ShortChannelID, + gossip bool) error + // PongBuf is a slice we'll reuse instead of allocating memory on the // heap. Since only reads will occur and no writes, there is no need // for any synchronization primitives. As a result, it's safe to share @@ -666,7 +678,65 @@ func (p *Brontide) loadActiveChannels(chans []*channeldb.OpenChannel) ( // cannot be loaded normally. var msgs []lnwire.Message + scidAliasNegotiated := p.hasNegotiatedScidAlias() + for _, dbChan := range chans { + hasScidFeature := dbChan.ChanType.HasScidAliasFeature() + if scidAliasNegotiated && !hasScidFeature { + // We'll request and store an alias, making sure that a + // gossiper mapping is not created for the alias to the + // real SCID. This is done because the peer and funding + // manager are not aware of each other's states and if + // we did not do this, we would accept alias channel + // updates after 6 confirmations, which would be buggy. + // We'll queue a funding_locked message with the new + // alias. This should technically be done *after* the + // reestablish, but this behavior is pre-existing since + // the funding manager may already queue a + // funding_locked before the channel_reestablish. + if !dbChan.IsPending { + aliasScid, err := p.cfg.RequestAlias() + if err != nil { + return nil, err + } + + err = p.cfg.AddLocalAlias( + aliasScid, dbChan.ShortChanID(), false, + ) + if err != nil { + return nil, err + } + + chanID := lnwire.NewChanIDFromOutPoint( + &dbChan.FundingOutpoint, + ) + + // Fetch the second commitment point to send in + // the funding_locked message. + second, err := dbChan.SecondCommitmentPoint() + if err != nil { + return nil, err + } + + fundingLockedMsg := lnwire.NewFundingLocked( + chanID, second, + ) + fundingLockedMsg.AliasScid = &aliasScid + + msgs = append(msgs, fundingLockedMsg) + } + + // If we've negotiated the option-scid-alias feature + // and this channel does not have ScidAliasFeature set + // to true due to an upgrade where the feature bit was + // turned on, we'll update the channel's database + // state. + err := dbChan.MarkScidAliasNegotiated() + if err != nil { + return nil, err + } + } + lnChan, err := lnwallet.NewLightningChannel( p.cfg.Signer, dbChan, p.cfg.SigPool, ) @@ -900,6 +970,7 @@ func (p *Brontide) addLink(chanPoint *wire.OutPoint, NotifyActiveChannel: p.cfg.ChannelNotifier.NotifyActiveChannelEvent, NotifyInactiveChannel: p.cfg.ChannelNotifier.NotifyInactiveChannelEvent, HtlcNotifier: p.cfg.HtlcNotifier, + GetAliases: p.cfg.GetAliases, } // Before adding our new link, purge the switch of any pending or live @@ -3054,6 +3125,14 @@ func (p *Brontide) RemoteFeatures() *lnwire.FeatureVector { return p.remoteFeatures } +// hasNegotiatedScidAlias returns true if we've negotiated the +// option-scid-alias feature bit with the peer. +func (p *Brontide) hasNegotiatedScidAlias() bool { + peerHas := p.remoteFeatures.HasFeature(lnwire.ScidAliasOptional) + localHas := p.cfg.Features.HasFeature(lnwire.ScidAliasOptional) + return peerHas && localHas +} + // sendInitMsg sends the Init message to the remote peer. This message contains // our currently supported local and global features. func (p *Brontide) sendInitMsg(legacyChan bool) error { diff --git a/peer/test_utils.go b/peer/test_utils.go index 1a9e6f61e3..f80705d550 100644 --- a/peer/test_utils.go +++ b/peer/test_utils.go @@ -340,7 +340,11 @@ func createTestPeer(notifier chainntnfs.ChainNotifier, OurPubKey: aliceKeyPub, OurKeyLoc: testKeyLoc, IsChannelActive: func(lnwire.ChannelID) bool { return true }, - ApplyChannelUpdate: func(*lnwire.ChannelUpdate) error { return nil }, + ApplyChannelUpdate: func(*lnwire.ChannelUpdate, + *wire.OutPoint, bool) error { + + return nil + }, }) if err != nil { return nil, nil, nil, err diff --git a/server.go b/server.go index fb08d9460a..fef25b1dcb 100644 --- a/server.go +++ b/server.go @@ -2138,7 +2138,9 @@ func (s *server) Stop() error { s.connMgr.Stop() // Shutdown the wallet, funding manager, and the rpc server. - s.chanStatusMgr.Stop() + if err := s.chanStatusMgr.Stop(); err != nil { + srvrLog.Warnf("failed to stop chanStatusMgr: %v", err) + } if err := s.htlcSwitch.Stop(); err != nil { srvrLog.Warnf("failed to stop htlcSwitch: %v", err) } @@ -3175,7 +3177,6 @@ func (s *server) NotifyWhenOnline(peerKey [33]byte, peerChan chan<- lnpeer.Peer) { s.mu.Lock() - defer s.mu.Unlock() // Compute the target peer's identifier. pubStr := string(peerKey[:]) @@ -3183,6 +3184,19 @@ func (s *server) NotifyWhenOnline(peerKey [33]byte, // Check if peer is connected. peer, ok := s.peersByPub[pubStr] if ok { + // Unlock here so that the mutex isn't held while we are + // waiting for the peer to become active. + s.mu.Unlock() + + // Wait until the peer signals that it is actually active + // rather than only in the server's maps. + select { + case <-peer.ActiveSignal(): + case <-peer.QuitSignal(): + // The peer quit so we'll just return. + return + } + // Connected, can return early. srvrLog.Debugf("Notifying that peer %x is online", peerKey) @@ -3199,6 +3213,7 @@ func (s *server) NotifyWhenOnline(peerKey [33]byte, s.peerConnectedListeners[pubStr] = append( s.peerConnectedListeners[pubStr], peerChan, ) + s.mu.Unlock() } // NotifyWhenOffline delivers a notification to the caller of when the peer with @@ -3696,6 +3711,9 @@ func (s *server) peerConnected(conn net.Conn, connReq *connmgr.ConnReq, PendingCommitInterval: s.cfg.PendingCommitInterval, ChannelCommitBatchSize: s.cfg.ChannelCommitBatchSize, HandleCustomMessage: s.handleCustomMessage, + GetAliases: s.aliasMgr.GetAliases, + RequestAlias: s.aliasMgr.RequestAlias, + AddLocalAlias: s.aliasMgr.AddLocalAlias, Quit: s.quit, } @@ -4444,9 +4462,30 @@ func (s *server) fetchLastChanUpdate() func(lnwire.ShortChannelID) ( } // applyChannelUpdate applies the channel update to the different sub-systems of -// the server. -func (s *server) applyChannelUpdate(update *lnwire.ChannelUpdate) error { - errChan := s.authGossiper.ProcessLocalAnnouncement(update) +// the server. The useAlias boolean denotes whether or not to send an alias in +// place of the real SCID. +func (s *server) applyChannelUpdate(update *lnwire.ChannelUpdate, + op *wire.OutPoint, useAlias bool) error { + + var ( + peerAlias *lnwire.ShortChannelID + defaultAlias lnwire.ShortChannelID + ) + + chanID := lnwire.NewChanIDFromOutPoint(op) + + // Fetch the peer's alias from the lnwire.ChannelID so it can be used + // in the ChannelUpdate if it hasn't been announced yet. + if useAlias { + foundAlias, _ := s.aliasMgr.GetPeerAlias(chanID) + if foundAlias != defaultAlias { + peerAlias = &foundAlias + } + } + + errChan := s.authGossiper.ProcessLocalAnnouncement( + update, discovery.RemoteAlias(peerAlias), + ) select { case err := <-errChan: return err