mirror of
https://github.com/lightningnetwork/lnd.git
synced 2025-10-10 10:53:11 +02:00
routing: global probability based mission control
Previously every payment had its own local mission control state which was in effect only for that payment. In this commit most of the local state is removed and payments all tap into the global mission control probability estimator. Furthermore the decay time of pruned edges and nodes is extended, so that observations about the network can better benefit future payment processes. Last, the probability function is transformed from a binary output to a gradual curve, allowing for a better trade off between candidate routes.
This commit is contained in:
@@ -319,6 +319,13 @@ func (e *EdgeLocator) String() string {
|
||||
return fmt.Sprintf("%v:%v", e.ChannelID, e.Direction)
|
||||
}
|
||||
|
||||
// edge is a combination of a channel and the node pubkeys of both of its
|
||||
// endpoints.
|
||||
type edge struct {
|
||||
from, to route.Vertex
|
||||
channel uint64
|
||||
}
|
||||
|
||||
// ChannelRouter is the layer 3 router within the Lightning stack. Below the
|
||||
// ChannelRouter is the HtlcSwitch, and below that is the Bitcoin blockchain
|
||||
// itself. The primary role of the ChannelRouter is to respond to queries for
|
||||
@@ -1769,7 +1776,9 @@ func (r *ChannelRouter) processSendError(paySession PaymentSession,
|
||||
|
||||
// Always determine chan id ourselves, because a channel
|
||||
// update with id may not be available.
|
||||
failedEdge, err := getFailedEdge(rt, route.Vertex(errVertex))
|
||||
failedEdge, failedAmt, err := getFailedEdge(
|
||||
rt, route.Vertex(errVertex),
|
||||
)
|
||||
if err != nil {
|
||||
return true
|
||||
}
|
||||
@@ -1801,13 +1810,11 @@ func (r *ChannelRouter) processSendError(paySession PaymentSession,
|
||||
// update to fail?
|
||||
if !updateOk {
|
||||
paySession.ReportEdgeFailure(
|
||||
failedEdge,
|
||||
failedEdge, 0,
|
||||
)
|
||||
}
|
||||
|
||||
paySession.ReportEdgePolicyFailure(
|
||||
route.NewVertex(errSource), failedEdge,
|
||||
)
|
||||
paySession.ReportEdgePolicyFailure(failedEdge)
|
||||
}
|
||||
|
||||
switch onionErr := fErr.FailureMessage.(type) {
|
||||
@@ -1898,7 +1905,7 @@ func (r *ChannelRouter) processSendError(paySession PaymentSession,
|
||||
// the update and continue.
|
||||
case *lnwire.FailChannelDisabled:
|
||||
r.applyChannelUpdate(&onionErr.Update, errSource)
|
||||
paySession.ReportEdgeFailure(failedEdge)
|
||||
paySession.ReportEdgeFailure(failedEdge, 0)
|
||||
return false
|
||||
|
||||
// It's likely that the outgoing channel didn't have
|
||||
@@ -1906,7 +1913,7 @@ func (r *ChannelRouter) processSendError(paySession PaymentSession,
|
||||
// now, and continue onwards with our path finding.
|
||||
case *lnwire.FailTemporaryChannelFailure:
|
||||
r.applyChannelUpdate(onionErr.Update, errSource)
|
||||
paySession.ReportEdgeFailure(failedEdge)
|
||||
paySession.ReportEdgeFailure(failedEdge, failedAmt)
|
||||
return false
|
||||
|
||||
// If the send fail due to a node not having the
|
||||
@@ -1931,7 +1938,7 @@ func (r *ChannelRouter) processSendError(paySession PaymentSession,
|
||||
// returning errors in order to attempt to black list
|
||||
// another node.
|
||||
case *lnwire.FailUnknownNextPeer:
|
||||
paySession.ReportEdgeFailure(failedEdge)
|
||||
paySession.ReportEdgeFailure(failedEdge, 0)
|
||||
return false
|
||||
|
||||
// If the node wasn't able to forward for which ever
|
||||
@@ -1962,14 +1969,12 @@ func (r *ChannelRouter) processSendError(paySession PaymentSession,
|
||||
// we'll prune the channel in both directions and
|
||||
// continue with the rest of the routes.
|
||||
case *lnwire.FailPermanentChannelFailure:
|
||||
paySession.ReportEdgeFailure(&EdgeLocator{
|
||||
ChannelID: failedEdge.ChannelID,
|
||||
Direction: 0,
|
||||
})
|
||||
paySession.ReportEdgeFailure(&EdgeLocator{
|
||||
ChannelID: failedEdge.ChannelID,
|
||||
Direction: 1,
|
||||
})
|
||||
paySession.ReportEdgeFailure(failedEdge, 0)
|
||||
paySession.ReportEdgeFailure(edge{
|
||||
from: failedEdge.to,
|
||||
to: failedEdge.from,
|
||||
channel: failedEdge.channel,
|
||||
}, 0)
|
||||
return false
|
||||
|
||||
default:
|
||||
@@ -1979,12 +1984,14 @@ func (r *ChannelRouter) processSendError(paySession PaymentSession,
|
||||
|
||||
// getFailedEdge tries to locate the failing channel given a route and the
|
||||
// pubkey of the node that sent the error. It will assume that the error is
|
||||
// associated with the outgoing channel of the error node.
|
||||
func getFailedEdge(route *route.Route, errSource route.Vertex) (
|
||||
*EdgeLocator, error) {
|
||||
// associated with the outgoing channel of the error node. As a second result,
|
||||
// it returns the amount sent over the edge.
|
||||
func getFailedEdge(route *route.Route, errSource route.Vertex) (edge,
|
||||
lnwire.MilliSatoshi, error) {
|
||||
|
||||
hopCount := len(route.Hops)
|
||||
fromNode := route.SourcePubKey
|
||||
amt := route.TotalAmount
|
||||
for i, hop := range route.Hops {
|
||||
toNode := hop.PubKeyBytes
|
||||
|
||||
@@ -2003,17 +2010,18 @@ func getFailedEdge(route *route.Route, errSource route.Vertex) (
|
||||
// If the errSource is the final hop, we assume that the failing
|
||||
// channel is the incoming channel.
|
||||
if errSource == fromNode || finalHopFailing {
|
||||
return newEdgeLocatorByPubkeys(
|
||||
hop.ChannelID,
|
||||
&fromNode,
|
||||
&toNode,
|
||||
), nil
|
||||
return edge{
|
||||
from: fromNode,
|
||||
to: toNode,
|
||||
channel: hop.ChannelID,
|
||||
}, amt, nil
|
||||
}
|
||||
|
||||
fromNode = toNode
|
||||
amt = hop.AmtToForward
|
||||
}
|
||||
|
||||
return nil, fmt.Errorf("cannot find error source node in route")
|
||||
return edge{}, 0, fmt.Errorf("cannot find error source node in route")
|
||||
}
|
||||
|
||||
// applyChannelUpdate validates a channel update and if valid, applies it to the
|
||||
|
Reference in New Issue
Block a user