routing: abstract path finding behind mission control
In this commit, from the PoV of the SendPayment method we now delegate all path finding+verification to missionControl. This change doesn’t materially affect anything, it simply expands the abstraction to make way for future features that more heavily utilize mission control.
This commit is contained in:
parent
dff3ad05f0
commit
b4273d1eaa
@ -3,6 +3,8 @@ package routing
|
|||||||
import (
|
import (
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/lightningnetwork/lnd/channeldb"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@ -49,6 +51,10 @@ type missionControl struct {
|
|||||||
// to that particular vertex.
|
// to that particular vertex.
|
||||||
failedVertexes map[vertex]time.Time
|
failedVertexes map[vertex]time.Time
|
||||||
|
|
||||||
|
graph *channeldb.ChannelGraph
|
||||||
|
|
||||||
|
selfNode *channeldb.LightningNode
|
||||||
|
|
||||||
sync.Mutex
|
sync.Mutex
|
||||||
|
|
||||||
// TODO(roasbeef): further counters, if vertex continually unavailable,
|
// TODO(roasbeef): further counters, if vertex continually unavailable,
|
||||||
@ -60,8 +66,12 @@ type missionControl struct {
|
|||||||
// newMissionControl returns a new instance of missionControl.
|
// newMissionControl returns a new instance of missionControl.
|
||||||
//
|
//
|
||||||
// TODO(roasbeef): persist memory
|
// TODO(roasbeef): persist memory
|
||||||
func newMissionControl() *missionControl {
|
func newMissionControl(g *channeldb.ChannelGraph,
|
||||||
|
s *channeldb.LightningNode) *missionControl {
|
||||||
|
|
||||||
return &missionControl{
|
return &missionControl{
|
||||||
|
graph: g,
|
||||||
|
selfNode: s,
|
||||||
failedEdges: make(map[uint64]time.Time),
|
failedEdges: make(map[uint64]time.Time),
|
||||||
failedVertexes: make(map[vertex]time.Time),
|
failedVertexes: make(map[vertex]time.Time),
|
||||||
}
|
}
|
||||||
@ -92,6 +102,45 @@ func (m *missionControl) ReportChannelFailure(e uint64) {
|
|||||||
m.Unlock()
|
m.Unlock()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// RequestRoute returns a route which is likely to be capable for successfully
|
||||||
|
// routing the specified HTLC payment to the target node. Initially the first
|
||||||
|
// set of paths returned from this method may encounter routing failure along
|
||||||
|
// the way, however as more payments are sent, mission control will start to
|
||||||
|
// build an up to date view of the network itself. With each payment a new area
|
||||||
|
// will be explored, which feeds into the recommendations made for routing.
|
||||||
|
//
|
||||||
|
// NOTE: This function is safe for concurrent access.
|
||||||
|
func (m *missionControl) RequestRoute(payment *LightningPayment,
|
||||||
|
height uint32) (*Route, error) {
|
||||||
|
|
||||||
|
// First, we'll query mission control for it's current recommendation
|
||||||
|
// on the edges/vertexes to ignore during path finding.
|
||||||
|
pruneView := m.GraphPruneView()
|
||||||
|
|
||||||
|
// TODO(roasbeef): sync logic amongst dist sys
|
||||||
|
|
||||||
|
// Taking into account this prune view, we'll attempt to locate a path
|
||||||
|
// to our destination, respecting the recommendations from
|
||||||
|
// missionControl.
|
||||||
|
path, err := findPath(nil, m.graph, m.selfNode, payment.Target,
|
||||||
|
pruneView.vertexes, pruneView.edges, payment.Amount)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// With the next candidate path found, we'll attempt to turn this into
|
||||||
|
// a route by applying the time-lock and fee requirements.
|
||||||
|
sourceVertex := newVertex(m.selfNode.PubKey)
|
||||||
|
route, err := newRoute(payment.Amount, sourceVertex, path, height)
|
||||||
|
if err != nil {
|
||||||
|
// TODO(roasbeef): return which edge/vertex didn't work
|
||||||
|
// out
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return route, err
|
||||||
|
}
|
||||||
|
|
||||||
// GraphPruneView returns a new graphPruneView instance which is to be
|
// GraphPruneView returns a new graphPruneView instance which is to be
|
||||||
// consulted during path finding. If a vertex/edge is found within the returned
|
// consulted during path finding. If a vertex/edge is found within the returned
|
||||||
// prune view, it is to be ignored as a goroutine has had issues routing
|
// prune view, it is to be ignored as a goroutine has had issues routing
|
||||||
|
@ -234,7 +234,7 @@ func New(cfg Config) (*ChannelRouter, error) {
|
|||||||
networkUpdates: make(chan *routingMsg),
|
networkUpdates: make(chan *routingMsg),
|
||||||
topologyClients: make(map[uint64]*topologyClient),
|
topologyClients: make(map[uint64]*topologyClient),
|
||||||
ntfnClientUpdates: make(chan *topologyClientUpdate),
|
ntfnClientUpdates: make(chan *topologyClientUpdate),
|
||||||
missionControl: newMissionControl(),
|
missionControl: newMissionControl(cfg.Graph, selfNode),
|
||||||
routeCache: make(map[routeTuple][]*Route),
|
routeCache: make(map[routeTuple][]*Route),
|
||||||
quit: make(chan struct{}),
|
quit: make(chan struct{}),
|
||||||
}, nil
|
}, nil
|
||||||
@ -1189,19 +1189,13 @@ func (r *ChannelRouter) SendPayment(payment *LightningPayment) ([32]byte, *Route
|
|||||||
|
|
||||||
// We'll continue until either our payment succeeds, or we encounter a
|
// We'll continue until either our payment succeeds, or we encounter a
|
||||||
// critical error during path finding.
|
// critical error during path finding.
|
||||||
sourceVertex := newVertex(r.selfNode.PubKey)
|
|
||||||
for {
|
for {
|
||||||
// First, we'll query mission control for it's current
|
// We'll kick things off by requesting a new route from mission
|
||||||
// recommendation on the edges/vertexes to ignore during path
|
// control, which will incoroporate the current best known
|
||||||
// finding.
|
// state of the channel graph and our past HTLC routing
|
||||||
pruneView := r.missionControl.GraphPruneView()
|
// successes/failures.
|
||||||
|
route, err := r.missionControl.RequestRoute(payment,
|
||||||
// Taking into account this prune view, we'll attempt to locate
|
uint32(currentHeight))
|
||||||
// a path to our destination, respecting the recommendations
|
|
||||||
// from missionControl.
|
|
||||||
path, err := findPath(nil, r.cfg.Graph, r.selfNode,
|
|
||||||
payment.Target, pruneView.vertexes, pruneView.edges,
|
|
||||||
payment.Amount)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// If we're unable to successfully make a payment using
|
// If we're unable to successfully make a payment using
|
||||||
// any of the routes we've found, then return an error.
|
// any of the routes we've found, then return an error.
|
||||||
@ -1214,17 +1208,6 @@ func (r *ChannelRouter) SendPayment(payment *LightningPayment) ([32]byte, *Route
|
|||||||
return preImage, nil, err
|
return preImage, nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// With the next candiate path found, we'll attempt to turn
|
|
||||||
// this into a route by applying the time-lock and fee
|
|
||||||
// requirements.
|
|
||||||
route, err := newRoute(payment.Amount, sourceVertex, path,
|
|
||||||
uint32(currentHeight))
|
|
||||||
if err != nil {
|
|
||||||
// TODO(roasbeef): return which edge/vertex didn't work
|
|
||||||
// out
|
|
||||||
return preImage, nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
log.Tracef("Attempting to send payment %x, using route: %v",
|
log.Tracef("Attempting to send payment %x, using route: %v",
|
||||||
payment.PaymentHash, newLogClosure(func() string {
|
payment.PaymentHash, newLogClosure(func() string {
|
||||||
return spew.Sdump(route)
|
return spew.Sdump(route)
|
||||||
|
Loading…
Reference in New Issue
Block a user