mirror of
https://github.com/lightningnetwork/lnd.git
synced 2025-10-10 18:33:21 +02:00
routing+server: add new QueryBandwidth method to reduce outbound failures
In this commit, we introduce a new method to the channel router's config struct: QueryBandwidth. This method allows the channel router to query for the up-to-date available bandwidth of a particular link. In the case that this link emanates from/to us, then we can query the switch to see if the link is active (if not bandwidth is zero), and return the current best estimate for the available bandwidth of the link. If the link, isn't one of ours, then we can thread through the total maximal capacity of the link. In order to implement this, the missionControl struct will now query the switch upon creation to obtain a fresh bandwidth snapshot. We take care to do this in a distinct db transaction in order to now introduced a circular waiting condition between the mutexes in bolt, and the channel state machine. The aim of this change is to reduce the number of unnecessary failures during HTLC payment routing as we'll now skip any links that are inactive, or just don't have enough bandwidth for the payment. Nodes that have several hundred channels (all of which in various states of activity and available bandwidth) should see a nice gain from this w.r.t payment latency.
This commit is contained in:
@@ -163,6 +163,14 @@ type Config struct {
|
||||
// GraphPruneInterval is used as an interval to determine how often we
|
||||
// should examine the channel graph to garbage collect zombie channels.
|
||||
GraphPruneInterval time.Duration
|
||||
|
||||
// QueryBandwidth is a method that allows the router to query the lower
|
||||
// link layer to determine the up to date available bandwidth at a
|
||||
// prospective link to be traversed. If the link isn't available, then
|
||||
// a value of zero should be returned. Otherwise, the current up to
|
||||
// date knowledge of the available bandwidth of the link should be
|
||||
// returned.
|
||||
QueryBandwidth func(edge *channeldb.ChannelEdgeInfo) lnwire.MilliSatoshi
|
||||
}
|
||||
|
||||
// routeTuple is an entry within the ChannelRouter's route cache. We cache
|
||||
@@ -283,18 +291,23 @@ func New(cfg Config) (*ChannelRouter, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &ChannelRouter{
|
||||
r := &ChannelRouter{
|
||||
cfg: &cfg,
|
||||
networkUpdates: make(chan *routingMsg),
|
||||
topologyClients: make(map[uint64]*topologyClient),
|
||||
ntfnClientUpdates: make(chan *topologyClientUpdate),
|
||||
missionControl: newMissionControl(cfg.Graph, selfNode),
|
||||
channelEdgeMtx: multimutex.NewMutex(),
|
||||
selfNode: selfNode,
|
||||
routeCache: make(map[routeTuple][]*Route),
|
||||
rejectCache: make(map[uint64]struct{}),
|
||||
quit: make(chan struct{}),
|
||||
}, nil
|
||||
}
|
||||
|
||||
r.missionControl = newMissionControl(
|
||||
cfg.Graph, selfNode, cfg.QueryBandwidth,
|
||||
)
|
||||
|
||||
return r, nil
|
||||
}
|
||||
|
||||
// Start launches all the goroutines the ChannelRouter requires to carry out
|
||||
@@ -1352,6 +1365,16 @@ func (r *ChannelRouter) FindRoutes(target *btcec.PublicKey,
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Before we open the db transaction below, we'll attempt to obtain a
|
||||
// set of bandwidth hints that can help us eliminate certain routes
|
||||
// early on in the path finding process.
|
||||
bandwidthHints, err := generateBandwidthHints(
|
||||
r.selfNode, r.cfg.QueryBandwidth,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
tx, err := r.cfg.Graph.Database().Begin(false)
|
||||
if err != nil {
|
||||
tx.Rollback()
|
||||
@@ -1363,6 +1386,7 @@ func (r *ChannelRouter) FindRoutes(target *btcec.PublicKey,
|
||||
// our source to the destination.
|
||||
shortestPaths, err := findPaths(
|
||||
tx, r.cfg.Graph, r.selfNode, target, amt, numPaths,
|
||||
bandwidthHints,
|
||||
)
|
||||
if err != nil {
|
||||
tx.Rollback()
|
||||
@@ -1567,9 +1591,13 @@ func (r *ChannelRouter) SendPayment(payment *LightningPayment) ([32]byte, *Route
|
||||
// Before starting the HTLC routing attempt, we'll create a fresh
|
||||
// payment session which will report our errors back to mission
|
||||
// control.
|
||||
paySession := r.missionControl.NewPaymentSession(
|
||||
paySession, err := r.missionControl.NewPaymentSession(
|
||||
payment.RouteHints, payment.Target,
|
||||
)
|
||||
if err != nil {
|
||||
return preImage, nil, fmt.Errorf("unable to create payment "+
|
||||
"session: %v", err)
|
||||
}
|
||||
|
||||
// We'll continue until either our payment succeeds, or we encounter a
|
||||
// critical error during path finding.
|
||||
|
Reference in New Issue
Block a user