Files
lnd/graph/db/interfaces.go
2025-08-06 09:56:21 +02:00

374 lines
18 KiB
Go

package graphdb
import (
"context"
"net"
"time"
"github.com/btcsuite/btcd/btcec/v2"
"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/lnwire"
"github.com/lightningnetwork/lnd/routing/route"
)
// NodeTraverser is an abstract read only interface that provides information
// about nodes and their edges. The interface is about providing fast read-only
// access to the graph and so if a cache is available, it should be used.
type NodeTraverser interface {
// ForEachNodeDirectedChannel calls the callback for every channel of
// the given node.
ForEachNodeDirectedChannel(nodePub route.Vertex,
cb func(channel *DirectedChannel) error, reset func()) error
// FetchNodeFeatures returns the features of the given node.
FetchNodeFeatures(nodePub route.Vertex) (*lnwire.FeatureVector, error)
}
// V1Store represents the main interface for the channel graph database for all
// channels and nodes gossiped via the V1 gossip protocol as defined in BOLT 7.
type V1Store interface { //nolint:interfacebloat
NodeTraverser
// AddLightningNode adds a vertex/node to the graph database. If the
// node is not in the database from before, this will add a new,
// unconnected one to the graph. If it is present from before, this will
// update that node's information. Note that this method is expected to
// only be called to update an already present node from a node
// announcement, or to insert a node found in a channel update.
AddLightningNode(ctx context.Context, node *models.LightningNode,
op ...batch.SchedulerOption) error
// AddrsForNode returns all known addresses for the target node public
// key that the graph DB is aware of. The returned boolean indicates if
// the given node is unknown to the graph DB or not.
AddrsForNode(ctx context.Context,
nodePub *btcec.PublicKey) (bool, []net.Addr, error)
// ForEachSourceNodeChannel iterates through all channels of the source
// node, executing the passed callback on each. The call-back is
// provided with the channel's outpoint, whether we have a policy for
// the channel and the channel peer's node information.
ForEachSourceNodeChannel(ctx context.Context,
cb func(chanPoint wire.OutPoint, havePolicy bool,
otherNode *models.LightningNode) error,
reset func()) error
// ForEachNodeChannel iterates through all channels of the given node,
// executing the passed callback with an edge info structure and the
// policies of each end of the channel. The first edge policy is the
// outgoing edge *to* the connecting node, while the second is the
// incoming edge *from* the connecting node. If the callback returns an
// error, then the iteration is halted with the error propagated back up
// to the caller.
//
// Unknown policies are passed into the callback as nil values.
ForEachNodeChannel(ctx context.Context, nodePub route.Vertex,
cb func(*models.ChannelEdgeInfo, *models.ChannelEdgePolicy,
*models.ChannelEdgePolicy) error, reset func()) error
// ForEachNodeCached is similar to forEachNode, but it returns
// DirectedChannel data to the call-back. If withAddrs is true, then
// the call-back will also be provided with the addresses associated
// with the node. The address retrieval will likely result in an
// additional round-trip to the database, so it should only be used if
// the addresses are actually needed.
//
// NOTE: The callback contents MUST not be modified.
ForEachNodeCached(ctx context.Context, withAddrs bool,
cb func(ctx context.Context, node route.Vertex,
addrs []net.Addr,
chans map[uint64]*DirectedChannel) error,
reset func()) error
// ForEachNode iterates through all the stored vertices/nodes in the
// graph, executing the passed callback with each node encountered. If
// the callback returns an error, then the transaction is aborted and
// the iteration stops early.
ForEachNode(ctx context.Context, cb func(*models.LightningNode) error,
reset func()) error
// ForEachNodeCacheable iterates through all the stored vertices/nodes
// in the graph, executing the passed callback with each node
// encountered. If the callback returns an error, then the transaction
// is aborted and the iteration stops early.
ForEachNodeCacheable(ctx context.Context, cb func(route.Vertex,
*lnwire.FeatureVector) error, reset func()) error
// LookupAlias attempts to return the alias as advertised by the target
// node.
LookupAlias(ctx context.Context, pub *btcec.PublicKey) (string, error)
// DeleteLightningNode starts a new database transaction to remove a
// vertex/node from the database according to the node's public key.
DeleteLightningNode(ctx context.Context, nodePub route.Vertex) error
// NodeUpdatesInHorizon returns all the known lightning node which have
// an update timestamp within the passed range. This method can be used
// by two nodes to quickly determine if they have the same set of up to
// date node announcements.
NodeUpdatesInHorizon(startTime,
endTime time.Time) ([]models.LightningNode, error)
// FetchLightningNode attempts to look up a target node by its identity
// public key. If the node isn't found in the database, then
// ErrGraphNodeNotFound is returned.
FetchLightningNode(ctx context.Context,
nodePub route.Vertex) (*models.LightningNode, error)
// HasLightningNode determines if the graph has a vertex identified by
// the target node identity public key. If the node exists in the
// database, a timestamp of when the data for the node was lasted
// updated is returned along with a true boolean. Otherwise, an empty
// time.Time is returned with a false boolean.
HasLightningNode(ctx context.Context, nodePub [33]byte) (time.Time,
bool, error)
// IsPublicNode is a helper method that determines whether the node with
// the given public key is seen as a public node in the graph from the
// graph's source node's point of view.
IsPublicNode(pubKey [33]byte) (bool, error)
// GraphSession will provide the call-back with access to a
// NodeTraverser instance which can be used to perform queries against
// the channel graph.
GraphSession(cb func(graph NodeTraverser) error, reset func()) error
// ForEachChannel iterates through all the channel edges stored within
// the graph and invokes the passed callback for each edge. The callback
// takes two edges as since this is a directed graph, both the in/out
// edges are visited. If the callback returns an error, then the
// transaction is aborted and the iteration stops early.
//
// NOTE: If an edge can't be found, or wasn't advertised, then a nil
// pointer for that particular channel edge routing policy will be
// passed into the callback.
ForEachChannel(ctx context.Context, cb func(*models.ChannelEdgeInfo,
*models.ChannelEdgePolicy, *models.ChannelEdgePolicy) error,
reset func()) error
// ForEachChannelCacheable iterates through all the channel edges stored
// within the graph and invokes the passed callback for each edge. The
// callback takes two edges as since this is a directed graph, both the
// in/out edges are visited. If the callback returns an error, then the
// transaction is aborted and the iteration stops early.
//
// NOTE: If an edge can't be found, or wasn't advertised, then a nil
// pointer for that particular channel edge routing policy will be
// passed into the callback.
//
// NOTE: this method is like ForEachChannel but fetches only the data
// required for the graph cache.
ForEachChannelCacheable(cb func(*models.CachedEdgeInfo,
*models.CachedEdgePolicy, *models.CachedEdgePolicy) error,
reset func()) error
// DisabledChannelIDs returns the channel ids of disabled channels.
// A channel is disabled when two of the associated ChanelEdgePolicies
// have their disabled bit on.
DisabledChannelIDs() ([]uint64, error)
// AddChannelEdge adds a new (undirected, blank) edge to the graph
// database. An undirected edge from the two target nodes are created.
// The information stored denotes the static attributes of the channel,
// such as the channelID, the keys involved in creation of the channel,
// and the set of features that the channel supports. The chanPoint and
// chanID are used to uniquely identify the edge globally within the
// database.
AddChannelEdge(ctx context.Context, edge *models.ChannelEdgeInfo,
op ...batch.SchedulerOption) error
// HasChannelEdge returns true if the database knows of a channel edge
// with the passed channel ID, and false otherwise. If an edge with that
// ID is found within the graph, then two time stamps representing the
// last time the edge was updated for both directed edges are returned
// along with the boolean. If it is not found, then the zombie index is
// checked and its result is returned as the second boolean.
HasChannelEdge(chanID uint64) (time.Time, time.Time, bool, bool,
error)
// DeleteChannelEdges removes edges with the given channel IDs from the
// database and marks them as zombies. This ensures that we're unable to
// re-add it to our database once again. If an edge does not exist
// within the database, then ErrEdgeNotFound will be returned. If
// strictZombiePruning is true, then when we mark these edges as
// zombies, we'll set up the keys such that we require the node that
// failed to send the fresh update to be the one that resurrects the
// channel from its zombie state. The markZombie bool denotes whether
// to mark the channel as a zombie.
DeleteChannelEdges(strictZombiePruning, markZombie bool,
chanIDs ...uint64) ([]*models.ChannelEdgeInfo, error)
// AddEdgeProof sets the proof of an existing edge in the graph
// database.
AddEdgeProof(chanID lnwire.ShortChannelID,
proof *models.ChannelAuthProof) error
// ChannelID attempt to lookup the 8-byte compact channel ID which maps
// to the passed channel point (outpoint). If the passed channel doesn't
// exist within the database, then ErrEdgeNotFound is returned.
ChannelID(chanPoint *wire.OutPoint) (uint64, error)
// HighestChanID returns the "highest" known channel ID in the channel
// graph. This represents the "newest" channel from the PoV of the
// chain. This method can be used by peers to quickly determine if
// they're graphs are in sync.
HighestChanID(ctx context.Context) (uint64, error)
// ChanUpdatesInHorizon returns all the known channel edges which have
// at least one edge that has an update timestamp within the specified
// horizon.
ChanUpdatesInHorizon(startTime, endTime time.Time) ([]ChannelEdge,
error)
// FilterKnownChanIDs takes a set of channel IDs and return the subset
// of chan ID's that we don't know and are not known zombies of the
// passed set. In other words, we perform a set difference of our set
// of chan ID's and the ones passed in. This method can be used by
// callers to determine the set of channels another peer knows of that
// we don't. The ChannelUpdateInfos for the known zombies is also
// returned.
FilterKnownChanIDs(chansInfo []ChannelUpdateInfo) ([]uint64,
[]ChannelUpdateInfo, error)
// FilterChannelRange returns the channel ID's of all known channels
// which were mined in a block height within the passed range. The
// channel IDs are grouped by their common block height. This method can
// be used to quickly share with a peer the set of channels we know of
// within a particular range to catch them up after a period of time
// offline. If withTimestamps is true then the timestamp info of the
// latest received channel update messages of the channel will be
// included in the response.
FilterChannelRange(startHeight, endHeight uint32, withTimestamps bool) (
[]BlockChannelRange, error)
// FetchChanInfos returns the set of channel edges that correspond to
// the passed channel ID's. If an edge is the query is unknown to the
// database, it will skipped and the result will contain only those
// edges that exist at the time of the query. This can be used to
// respond to peer queries that are seeking to fill in gaps in their
// view of the channel graph.
FetchChanInfos(chanIDs []uint64) ([]ChannelEdge, error)
// FetchChannelEdgesByOutpoint attempts to lookup the two directed edges
// for the channel identified by the funding outpoint. If the channel
// can't be found, then ErrEdgeNotFound is returned. A struct which
// houses the general information for the channel itself is returned as
// well as two structs that contain the routing policies for the channel
// in either direction.
FetchChannelEdgesByOutpoint(op *wire.OutPoint) (
*models.ChannelEdgeInfo, *models.ChannelEdgePolicy,
*models.ChannelEdgePolicy, error)
// FetchChannelEdgesByID attempts to lookup the two directed edges for
// the channel identified by the channel ID. If the channel can't be
// found, then ErrEdgeNotFound is returned. A struct which houses the
// general information for the channel itself is returned as well as
// two structs that contain the routing policies for the channel in
// either direction.
//
// ErrZombieEdge can be returned if the edge is currently marked as a
// zombie within the database. In this case, the ChannelEdgePolicy's
// will be nil, and the ChannelEdgeInfo will only include the public
// keys of each node.
FetchChannelEdgesByID(chanID uint64) (
*models.ChannelEdgeInfo, *models.ChannelEdgePolicy,
*models.ChannelEdgePolicy, error)
// ChannelView returns the verifiable edge information for each active
// channel within the known channel graph. The set of UTXO's (along with
// their scripts) returned are the ones that need to be watched on chain
// to detect channel closes on the resident blockchain.
ChannelView() ([]EdgePoint, error)
// MarkEdgeZombie attempts to mark a channel identified by its channel
// ID as a zombie. This method is used on an ad-hoc basis, when channels
// need to be marked as zombies outside the normal pruning cycle.
MarkEdgeZombie(chanID uint64,
pubKey1, pubKey2 [33]byte) error
// MarkEdgeLive clears an edge from our zombie index, deeming it as
// live.
MarkEdgeLive(chanID uint64) error
// IsZombieEdge returns whether the edge is considered zombie. If it is
// a zombie, then the two node public keys corresponding to this edge
// are also returned.
IsZombieEdge(chanID uint64) (bool, [33]byte, [33]byte, error)
// NumZombies returns the current number of zombie channels in the
// graph.
NumZombies() (uint64, error)
// PutClosedScid stores a SCID for a closed channel in the database.
// This is so that we can ignore channel announcements that we know to
// be closed without having to validate them and fetch a block.
PutClosedScid(scid lnwire.ShortChannelID) error
// IsClosedScid checks whether a channel identified by the passed in
// scid is closed. This helps avoid having to perform expensive
// validation checks.
IsClosedScid(scid lnwire.ShortChannelID) (bool, error)
// UpdateEdgePolicy updates the edge routing policy for a single
// directed edge within the database for the referenced channel. The
// `flags` attribute within the ChannelEdgePolicy determines which of
// the directed edges are being updated. If the flag is 1, then the
// first node's information is being updated, otherwise it's the second
// node's information. The node ordering is determined by the
// lexicographical ordering of the identity public keys of the nodes on
// either side of the channel.
UpdateEdgePolicy(ctx context.Context, edge *models.ChannelEdgePolicy,
op ...batch.SchedulerOption) (route.Vertex, route.Vertex, error)
// SourceNode returns the source node of the graph. The source node is
// treated as the center node within a star-graph. This method may be
// used to kick off a path finding algorithm in order to explore the
// reachability of another node based off the source node.
SourceNode(ctx context.Context) (*models.LightningNode, error)
// SetSourceNode sets the source node within the graph database. The
// source node is to be used as the center of a star-graph within path
// finding algorithms.
SetSourceNode(ctx context.Context,
node *models.LightningNode) error
// PruneTip returns the block height and hash of the latest block that
// has been used to prune channels in the graph. Knowing the "prune tip"
// allows callers to tell if the graph is currently in sync with the
// current best known UTXO state.
PruneTip() (*chainhash.Hash, uint32, error)
// PruneGraphNodes is a garbage collection method which attempts to
// prune out any nodes from the channel graph that are currently
// unconnected. This ensures 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.
PruneGraphNodes() ([]route.Vertex, error)
// 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 along
// with any pruned nodes are returned if the function succeeds without
// error.
PruneGraph(spentOutputs []*wire.OutPoint,
blockHash *chainhash.Hash, blockHeight uint32) (
[]*models.ChannelEdgeInfo, []route.Vertex, error)
// DisconnectBlockAtHeight is used to indicate that the block specified
// by the passed height has been disconnected from the main chain. This
// will "rewind" the graph back to the height below, deleting channels
// that are no longer confirmed from the graph. The prune log will be
// set to the last prune height valid for the remaining chain.
// Channels that were removed from the graph resulting from the
// disconnected block are returned.
DisconnectBlockAtHeight(height uint32) ([]*models.ChannelEdgeInfo,
error)
}