Skip to content

Commit

Permalink
temp: remove kvdb.RTx from Router
Browse files Browse the repository at this point in the history
  • Loading branch information
ellemouton committed Jun 21, 2024
1 parent 5f00b80 commit 009d60d
Show file tree
Hide file tree
Showing 15 changed files with 339 additions and 206 deletions.
141 changes: 141 additions & 0 deletions channeldb/graphsession/graph_session.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
package graphsession

import (
"fmt"

"github.com/lightningnetwork/lnd/channeldb"
"github.com/lightningnetwork/lnd/kvdb"
"github.com/lightningnetwork/lnd/lnwire"
"github.com/lightningnetwork/lnd/routing"
"github.com/lightningnetwork/lnd/routing/route"
)

// Factory implements the routing.GraphSessionFactory and can be used to start
// a session with a ReadOnlyGraph.
type Factory struct {
graph ReadOnlyGraph
}

// NewFactory constructs a new Factory which can then be used to start a new
// Session.
func NewFactory(graph ReadOnlyGraph) routing.GraphSessionFactory {
return &Factory{
graph: graph,
}
}

// NewSession will produce a new GraphSession to use for a path-finding session.
// The caller MUST call Close once it has finished using the session.
//
// This is part of the routing.GraphSessionFactory interface.
func (g *Factory) NewSession() (routing.GraphSession, error) {
tx, err := g.graph.NewPathFindTx()
if err != nil {
return nil, err
}

return &Session{
graph: g.graph,
tx: tx,
}, nil
}

// A compile-time check to ensure that Factory implements the
// routing.GraphSessionFactory interface.
var _ routing.GraphSessionFactory = (*Factory)(nil)

// Session is an implementation of the routing.GraphSession interface and can
// be used to access the backing channel graph.
type Session struct {
graph graph
tx kvdb.RTx
}

// NewRoutingGraph constructs a Session that which does not first start a
// read-only transaction and so each call on the routing.Graph will create a
// new transaction.
func NewRoutingGraph(graph ReadOnlyGraph) routing.Graph {
return &Session{
graph: graph,
}
}

// Graph returns the backing graph.
//
// NOTE: this is part of the routing.GraphSession interface.
func (g *Session) Graph() routing.Graph {
return g
}

// Close closes the read-only transaction being used to access the backing
// graph. If no transaction was started then this is a no-op.
//
// NOTE: this is part of the routing.GraphSession interface.
func (g *Session) Close() error {
if g.tx == nil {
return nil
}

err := g.tx.Rollback()
if err != nil {
return fmt.Errorf("error closing db tx: %w", err)
}

return nil
}

// ForEachNodeChannel calls the callback for every channel of the given node.
//
// NOTE: Part of the routing.Graph interface.
func (g *Session) ForEachNodeChannel(nodePub route.Vertex,
cb func(channel *channeldb.DirectedChannel) error) error {

return g.graph.ForEachNodeDirectedChannel(g.tx, nodePub, cb)
}

// FetchNodeFeatures returns the features of the given node. If the node is
// unknown, assume no additional features are supported.
//
// NOTE: Part of the routing.Graph interface.
func (g *Session) FetchNodeFeatures(nodePub route.Vertex) (
*lnwire.FeatureVector, error) {

return g.graph.FetchNodeFeatures(nodePub)
}

// A compile-time check to ensure that *Session implements the
// routing.GraphSession interface.
var _ routing.GraphSession = (*Session)(nil)

// ReadOnlyGraph is a graph extended with a call to create a new read-only
// transaction that can then be used to make further queries to the graph.
type ReadOnlyGraph interface {
// NewPathFindTx returns a new read transaction that can be used for a
// single path finding session. Will return nil if the graph cache is
// enabled.
NewPathFindTx() (kvdb.RTx, error)

graph
}

// graph describes the API necessary for a graph source to have in order to be
// used by the Router for pathfinding.
type graph interface {
// ForEachNodeDirectedChannel iterates through all channels of a given
// node, executing the passed callback on the directed edge representing
// the channel and its incoming policy. 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.
ForEachNodeDirectedChannel(tx kvdb.RTx, node route.Vertex,
cb func(channel *channeldb.DirectedChannel) error) error

// FetchNodeFeatures returns the features of a given node. If no
// features are known for the node, an empty feature vector is returned.
FetchNodeFeatures(node route.Vertex) (*lnwire.FeatureVector, error)
}

// A compile-time check to ensure that *channeldb.ChannelGraph implements the
// graph interface.
var _ graph = (*channeldb.ChannelGraph)(nil)
4 changes: 2 additions & 2 deletions routing/bandwidth.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ type bandwidthManager struct {
// hints for the edges we directly have open ourselves. Obtaining these hints
// allows us to reduce the number of extraneous attempts as we can skip channels
// that are inactive, or just don't have enough bandwidth to carry the payment.
func newBandwidthManager(graph routingGraph, sourceNode route.Vertex,
func newBandwidthManager(graph Graph, sourceNode route.Vertex,
linkQuery getLinkQuery) (*bandwidthManager, error) {

manager := &bandwidthManager{
Expand All @@ -49,7 +49,7 @@ func newBandwidthManager(graph routingGraph, sourceNode route.Vertex,

// First, we'll collect the set of outbound edges from the target
// source node and add them to our bandwidth manager's map of channels.
err := graph.forEachNodeChannel(sourceNode,
err := graph.ForEachNodeChannel(sourceNode,
func(channel *channeldb.DirectedChannel) error {
shortID := lnwire.NewShortChanIDFromInt(
channel.ChannelID,
Expand Down
123 changes: 25 additions & 98 deletions routing/graph.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,125 +5,52 @@ import (

"github.com/btcsuite/btcd/btcutil"
"github.com/lightningnetwork/lnd/channeldb"
"github.com/lightningnetwork/lnd/kvdb"
"github.com/lightningnetwork/lnd/lnwire"
"github.com/lightningnetwork/lnd/routing/route"
)

// routingGraph is an abstract interface that provides information about nodes
// and edges to pathfinding.
type routingGraph interface {
// forEachNodeChannel calls the callback for every channel of the given
// node.
forEachNodeChannel(nodePub route.Vertex,
cb func(channel *channeldb.DirectedChannel) error) error

// fetchNodeFeatures returns the features of the given node.
fetchNodeFeatures(nodePub route.Vertex) (*lnwire.FeatureVector, error)
// GraphSessionFactory can be used to produce a new GraphSession instance which
// can then be used for a path-finding session. In some instances, a "session"

Check failure on line 13 in routing/graph.go

View workflow job for this annotation

GitHub Actions / lint code

Comment should end in a period (godot)
type GraphSessionFactory interface {
// NewSession will produce a new GraphSession to use for a path-finding
// session.
NewSession() (GraphSession, error)
}

// ReadOnlyGraph is a Graph extended with a call to create a new read-only
// transaction that can then be used to make further queries to the Graph.
type ReadOnlyGraph interface {
// NewPathFindTx returns a new read transaction that can be used for a
// single path finding session. Will return nil if the graph cache is
// enabled.
NewPathFindTx() (kvdb.RTx, error)
// GraphSession describes a new read session with a Graph backend. It must be
// closed using its Close method after path-finding is complete.
type GraphSession interface {
// Graph returns the Graph that this session gives access to.
Graph() Graph

Graph
// Close closes the GraphSession and must be called once path-finding
// using this GraphSession is complete.
Close() error
}

// Graph describes the API necessary for a graph source to have in order to be
// used by the Router for pathfinding.
// Graph is an abstract interface that provides information about nodes
// and edges to pathfinding.
type Graph interface {
// ForEachNodeDirectedChannel iterates through all channels of a given
// node, executing the passed callback on the directed edge representing
// the channel and its incoming policy. 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.
ForEachNodeDirectedChannel(tx kvdb.RTx, node route.Vertex,
// ForEachNodeChannel calls the callback for every channel of the given
// node.
ForEachNodeChannel(nodePub route.Vertex,
cb func(channel *channeldb.DirectedChannel) error) error

// FetchNodeFeatures returns the features of a given node. If no
// features are known for the node, an empty feature vector is returned.
FetchNodeFeatures(node route.Vertex) (*lnwire.FeatureVector, error)
}

// CachedGraph is a routingGraph implementation that retrieves from the
// database.
type CachedGraph struct {
graph Graph
tx kvdb.RTx
source route.Vertex
}

// A compile time assertion to make sure CachedGraph implements the routingGraph
// interface.
var _ routingGraph = (*CachedGraph)(nil)

// NewCachedGraph instantiates a new db-connected routing graph. It implicitly
// instantiates a new read transaction if withReadLock is true and if the
// backing Graph supports it.
func NewCachedGraph(sourceNodePubKey route.Vertex,
graph ReadOnlyGraph, withReadLock bool) (*CachedGraph, error) {

cachedGraph := &CachedGraph{
graph: graph,
source: sourceNodePubKey,
}

if withReadLock {
var err error
cachedGraph.tx, err = graph.NewPathFindTx()
if err != nil {
return nil, err
}
}

return cachedGraph, nil
}

// Close attempts to close the underlying db transaction. This is a no-op in
// case the underlying graph uses an in-memory cache.
func (g *CachedGraph) Close() error {
if g.tx == nil {
return nil
}

return g.tx.Rollback()
}

// forEachNodeChannel calls the callback for every channel of the given node.
//
// NOTE: Part of the routingGraph interface.
func (g *CachedGraph) forEachNodeChannel(nodePub route.Vertex,
cb func(channel *channeldb.DirectedChannel) error) error {

return g.graph.ForEachNodeDirectedChannel(g.tx, nodePub, cb)
}

// fetchNodeFeatures returns the features of the given node. If the node is
// unknown, assume no additional features are supported.
//
// NOTE: Part of the routingGraph interface.
func (g *CachedGraph) fetchNodeFeatures(nodePub route.Vertex) (
*lnwire.FeatureVector, error) {

return g.graph.FetchNodeFeatures(nodePub)
// FetchNodeFeatures returns the features of the given node.
FetchNodeFeatures(nodePub route.Vertex) (*lnwire.FeatureVector, error)
}

// FetchAmountPairCapacity determines the maximal public capacity between two
// nodes depending on the amount we try to send.
func (g *CachedGraph) FetchAmountPairCapacity(nodeFrom, nodeTo route.Vertex,
amount lnwire.MilliSatoshi) (btcutil.Amount, error) {
func FetchAmountPairCapacity(g Graph, source, nodeFrom,
nodeTo route.Vertex, amount lnwire.MilliSatoshi) (btcutil.Amount,
error) {

// Create unified edges for all incoming connections.
//
// Note: Inbound fees are not used here because this method is only used
// by a deprecated router rpc.
u := newNodeEdgeUnifier(g.source, nodeTo, false, nil)
u := newNodeEdgeUnifier(source, nodeTo, false, nil)

err := u.addGraphPolicies(g)
if err != nil {
Expand Down
Loading

0 comments on commit 009d60d

Please sign in to comment.