From cc4fcbf83882c7afb24c07580ef735319adef8d4 Mon Sep 17 00:00:00 2001 From: Elle Mouton Date: Mon, 17 Feb 2025 12:58:51 -0300 Subject: [PATCH] graph/db: move cache writes for Prune methods This commit moves the cache writes for PruneGraphNodes and PruneGraph from the KVStore to the ChannelGraph. --- docs/release-notes/release-notes-0.19.0.md | 1 + graph/db/graph.go | 64 ++++++++++++++++++++++ graph/db/kv_store.go | 61 ++++++++------------- 3 files changed, 87 insertions(+), 39 deletions(-) diff --git a/docs/release-notes/release-notes-0.19.0.md b/docs/release-notes/release-notes-0.19.0.md index d6adeede4..54941074c 100644 --- a/docs/release-notes/release-notes-0.19.0.md +++ b/docs/release-notes/release-notes-0.19.0.md @@ -325,6 +325,7 @@ The underlying functionality between those two options remain the same. - [1](https://github.com/lightningnetwork/lnd/pull/9533) - [2](https://github.com/lightningnetwork/lnd/pull/9545) - [3](https://github.com/lightningnetwork/lnd/pull/9550) + - [4](https://github.com/lightningnetwork/lnd/pull/9551) * [Golang was updated to `v1.22.11`](https://github.com/lightningnetwork/lnd/pull/9462). diff --git a/graph/db/graph.go b/graph/db/graph.go index c3f195bc0..6185de410 100644 --- a/graph/db/graph.go +++ b/graph/db/graph.go @@ -4,6 +4,8 @@ import ( "sync" "time" + "github.com/btcsuite/btcd/chaincfg/chainhash" + "github.com/btcsuite/btcd/wire" "github.com/lightningnetwork/lnd/batch" "github.com/lightningnetwork/lnd/graph/db/models" "github.com/lightningnetwork/lnd/kvdb" @@ -322,3 +324,65 @@ func (c *ChannelGraph) DisconnectBlockAtHeight(height uint32) ( return edges, nil } + +// PruneGraph prunes newly closed channels from the channel graph in response +// to a new block being solved on the network. Any transactions which spend the +// funding output of any known channels within he graph will be deleted. +// Additionally, the "prune tip", or the last block which has been used to +// prune the graph is stored so callers can ensure the graph is fully in sync +// with the current UTXO state. A slice of channels that have been closed by +// the target block are returned if the function succeeds without error. +func (c *ChannelGraph) PruneGraph(spentOutputs []*wire.OutPoint, + blockHash *chainhash.Hash, blockHeight uint32) ( + []*models.ChannelEdgeInfo, error) { + + c.cacheMu.Lock() + defer c.cacheMu.Unlock() + + edges, nodes, err := c.KVStore.PruneGraph( + spentOutputs, blockHash, blockHeight, + ) + if err != nil { + return nil, err + } + + if c.graphCache != nil { + for _, edge := range edges { + c.graphCache.RemoveChannel( + edge.NodeKey1Bytes, edge.NodeKey2Bytes, + edge.ChannelID, + ) + } + + for _, node := range nodes { + c.graphCache.RemoveNode(node) + } + + log.Debugf("Pruned graph, cache now has %s", + c.graphCache.Stats()) + } + + return edges, nil +} + +// PruneGraphNodes is a garbage collection method which attempts to prune out +// any nodes from the channel graph that are currently unconnected. This ensure +// that we only maintain a graph of reachable nodes. In the event that a pruned +// node gains more channels, it will be re-added back to the graph. +func (c *ChannelGraph) PruneGraphNodes() error { + c.cacheMu.Lock() + defer c.cacheMu.Unlock() + + nodes, err := c.KVStore.PruneGraphNodes() + if err != nil { + return err + } + + if c.graphCache != nil { + for _, node := range nodes { + c.graphCache.RemoveNode(node) + } + } + + return nil +} diff --git a/graph/db/kv_store.go b/graph/db/kv_store.go index 9d784bf0d..486971e03 100644 --- a/graph/db/kv_store.go +++ b/graph/db/kv_store.go @@ -1316,15 +1316,19 @@ const ( // Additionally, the "prune tip", or the last block which has been used to // prune the graph is stored so callers can ensure the graph is fully in sync // with the current UTXO state. A slice of channels that have been closed by -// the target block are returned if the function succeeds without error. +// the target block along with any pruned nodes are returned if the function +// succeeds without error. func (c *KVStore) PruneGraph(spentOutputs []*wire.OutPoint, blockHash *chainhash.Hash, blockHeight uint32) ( - []*models.ChannelEdgeInfo, error) { + []*models.ChannelEdgeInfo, []route.Vertex, error) { c.cacheMu.Lock() defer c.cacheMu.Unlock() - var chansClosed []*models.ChannelEdgeInfo + var ( + chansClosed []*models.ChannelEdgeInfo + prunedNodes []route.Vertex + ) err := kvdb.Update(c.db, func(tx kvdb.RwTx) error { // First grab the edges bucket which houses the information @@ -1387,14 +1391,6 @@ func (c *KVStore) PruneGraph(spentOutputs []*wire.OutPoint, return err } - if c.graphCache != nil { - c.graphCache.RemoveChannel( - edgeInfo.NodeKey1Bytes, - edgeInfo.NodeKey2Bytes, - edgeInfo.ChannelID, - ) - } - chansClosed = append(chansClosed, edgeInfo) } @@ -1427,23 +1423,15 @@ func (c *KVStore) PruneGraph(spentOutputs []*wire.OutPoint, // Now that the graph has been pruned, we'll also attempt to // prune any nodes that have had a channel closed within the // latest block. - prunedNodes, err := c.pruneGraphNodes(nodes, edgeIndex) - if err != nil { - return err - } + prunedNodes, err = c.pruneGraphNodes(nodes, edgeIndex) - if c.graphCache != nil { - for _, nodePubKey := range prunedNodes { - c.graphCache.RemoveNode(nodePubKey) - } - } - - return nil + return err }, func() { chansClosed = nil + prunedNodes = nil }) if err != nil { - return nil, err + return nil, nil, err } for _, channel := range chansClosed { @@ -1451,20 +1439,16 @@ func (c *KVStore) PruneGraph(spentOutputs []*wire.OutPoint, c.chanCache.remove(channel.ChannelID) } - if c.graphCache != nil { - log.Debugf("Pruned graph, cache now has %s", - c.graphCache.Stats()) - } - - return chansClosed, nil + return chansClosed, prunedNodes, nil } // PruneGraphNodes is a garbage collection method which attempts to prune out // any nodes from the channel graph that are currently unconnected. This ensure // that we only maintain a graph of reachable nodes. In the event that a pruned // node gains more channels, it will be re-added back to the graph. -func (c *KVStore) PruneGraphNodes() error { - return kvdb.Update(c.db, func(tx kvdb.RwTx) error { +func (c *KVStore) PruneGraphNodes() ([]route.Vertex, error) { + var prunedNodes []route.Vertex + err := kvdb.Update(c.db, func(tx kvdb.RwTx) error { nodes := tx.ReadWriteBucket(nodeBucket) if nodes == nil { return ErrGraphNodesNotFound @@ -1478,19 +1462,18 @@ func (c *KVStore) PruneGraphNodes() error { return ErrGraphNoEdgesFound } - prunedNodes, err := c.pruneGraphNodes(nodes, edgeIndex) + var err error + prunedNodes, err = c.pruneGraphNodes(nodes, edgeIndex) if err != nil { return err } - if c.graphCache != nil { - for _, nodePubKey := range prunedNodes { - c.graphCache.RemoveNode(nodePubKey) - } - } - return nil - }, func() {}) + }, func() { + prunedNodes = nil + }) + + return prunedNodes, err } // pruneGraphNodes attempts to remove any nodes from the graph who have had a