graph/db: handle topology updates in a single location

In this commit, we ensure that any topology update is forced to go via
the `handleTopologySubscriptions` handler so that client subscriptions
and updates are handled correctly and in the correct order.

This removes a bug that could result from a client missing a
notification about a channel being closed if the client is subscribed
and shortly after, `PruneGraph` is called which would notify all
subscribed clients and possibly do so before the client subscription has
actually been persisted.
This commit is contained in:
Elle Mouton committed 2025-05-12 14:42:22 +02:00
1 parent ee25c228e9
commit 0155d5d7b0
3 files changed
+18 -4

No files matched your search

@@ -128,6 +128,9 @@ when running LND with an aux component injected (custom channels).
such that the probability is evaluated quicker and to be more accurate in such that the probability is evaluated quicker and to be more accurate in
outdated scenarios. outdated scenarios.
* [Fix a bug](https://github.com/lightningnetwork/lnd/pull/9798) that could
result in a new topology client missing a channel-close notifications.
# New Features # New Features
* Add support for [archiving channel backup](https://github.com/lightningnetwork/lnd/pull/9232) * Add support for [archiving channel backup](https://github.com/lightningnetwork/lnd/pull/9232)
+6 -3
View File
@@ -492,9 +492,12 @@ func (c *ChannelGraph) PruneGraph(spentOutputs []*wire.OutPoint,
closeSummaries := createCloseSummaries( closeSummaries := createCloseSummaries(
blockHeight, edges..., blockHeight, edges...,
) )
c.notifyTopologyChange(&TopologyChange{
ClosedChannels: closeSummaries, select {
}) case c.topologyUpdate <- closeSummaries:
case <-c.quit:
return nil, ErrChanGraphShuttingDown
}
} }
return edges, nil return edges, nil
+9 -1
View File
@@ -149,6 +149,9 @@ type topologyClient struct {
// notifyTopologyChange notifies all registered clients of a new change in // notifyTopologyChange notifies all registered clients of a new change in
// graph topology in a non-blocking. // graph topology in a non-blocking.
//
// NOTE: this should only ever be called from a call-stack originating from the
// handleTopologySubscriptions handler.
func (c *ChannelGraph) notifyTopologyChange(topologyDiff *TopologyChange) { func (c *ChannelGraph) notifyTopologyChange(topologyDiff *TopologyChange) {
// notifyClient is a helper closure that will send topology updates to // notifyClient is a helper closure that will send topology updates to
// the given client. // the given client.
@@ -194,7 +197,8 @@ func (c *ChannelGraph) notifyTopologyChange(topologyDiff *TopologyChange) {
// handleTopologyUpdate is responsible for sending any topology changes // handleTopologyUpdate is responsible for sending any topology changes
// notifications to registered clients. // notifications to registered clients.
// //
// NOTE: must be run inside goroutine. // NOTE: must be run inside goroutine and must only ever be called from within
// handleTopologySubscriptions.
func (c *ChannelGraph) handleTopologyUpdate(update any) { func (c *ChannelGraph) handleTopologyUpdate(update any) {
defer c.wg.Done() defer c.wg.Done()
@@ -445,6 +449,10 @@ func (c *ChannelGraph) addToTopologyChange(update *TopologyChange,
edgeUpdate) edgeUpdate)
return nil return nil
case []*ClosedChanSummary:
update.ClosedChannels = append(update.ClosedChannels, m...)
return nil
default: default:
return fmt.Errorf("unable to add to topology change, "+ return fmt.Errorf("unable to add to topology change, "+
"unknown message type %T", msg) "unknown message type %T", msg)