peer: always send channel update on reconnect

We have existing logic to attempt to reliably send a channel update to
the remote peer. In the wild, we've seen this fail, as it's possible
right when we send the update the peer disconnects.

In this commit, we implement a simple fix which is just to send the chan
update each time we connect to the remote party.

Fixes https://github.com/lightningnetwork/lnd/issues/6870.
This commit is contained in:
Olaoluwa Osuntokun committed 2024-08-07 17:48:50 -07:00
1 parent a449a5d132
commit 9acad37f57
4 files changed
+131 -2

No files matched your search

+70
View File
@@ -787,7 +787,9 @@ func (p *Brontide) Start() error {
//
// TODO(wilmer): Remove this once we're able to query for node
// announcements through their timestamps.
p.wg.Add(2)
go p.maybeSendNodeAnn(activeChans)
go p.maybeSendChannelUpdates()
return nil
}
@@ -1218,6 +1220,8 @@ func (p *Brontide) addLink(chanPoint *wire.OutPoint,
// maybeSendNodeAnn sends our node announcement to the remote peer if at least
// one confirmed public channel exists with them.
func (p *Brontide) maybeSendNodeAnn(channels []*channeldb.OpenChannel) {
defer p.wg.Done()
hasConfirmedPublicChan := false
for _, channel := range channels {
if channel.IsPending {
@@ -1245,6 +1249,72 @@ func (p *Brontide) maybeSendNodeAnn(channels []*channeldb.OpenChannel) {
}
}
// maybeSendChannelUpdates sends our channel updates to the remote peer if we
// have any active channels with them.
func (p *Brontide) maybeSendChannelUpdates() {
defer p.wg.Done()
// If we don't have any active channels, then we can exit early.
if p.activeChannels.Len() == 0 {
return
}
maybeSendUpd := func(cid lnwire.ChannelID,
lnChan *lnwallet.LightningChannel) error {
// Nil channels are pending, so we'll skip them.
if lnChan == nil {
return nil
}
dbChan := lnChan.State()
scid := func() lnwire.ShortChannelID {
switch {
// Otherwise if it's a zero conf channel and confirmed,
// then we need to use the "real" scid.
case dbChan.IsZeroConf() && dbChan.ZeroConfConfirmed():
return dbChan.ZeroConfRealScid()
// Otherwise, we can use the normal scid.
default:
return dbChan.ShortChanID()
}
}()
// Now that we know the channel is in a good state, we'll try
// to fetch the update to send to the remote peer. If the
// channel is pending, and not a zero conf channel, we'll get
// an error here which we'll ignore.
chanUpd, err := p.cfg.FetchLastChanUpdate(scid)
if err != nil {
p.log.Debugf("Unable to fetch channel update for "+
"ChannelPoint(%v), scid=%v: %v",
dbChan.FundingOutpoint, dbChan.ShortChanID, err)
return nil
}
p.log.Debugf("Sending channel update for ChannelPoint(%v), "+
"scid=%v", dbChan.FundingOutpoint, dbChan.ShortChanID)
// We'll send it as a normal message instead of using the lazy
// queue to prioritize transmission of the fresh update.
if err := p.SendMessage(false, chanUpd); err != nil {
err := fmt.Errorf("unable to send channel update for "+
"ChannelPoint(%v), scid=%v: %w",
dbChan.FundingOutpoint, dbChan.ShortChanID(),
err)
p.log.Errorf(err.Error())
return err
}
return nil
}
p.activeChannels.ForEach(maybeSendUpd)
}
// WaitForDisconnect waits until the peer has disconnected. A peer may be
// disconnected if the local or remote side terminates the connection, or an
// irrecoverable protocol error has been encountered. This method will only