routing: add new NewPaymentSessionFromRoutes function instead of interface

In this commit, we modify the recent refactoring of the mission control
sub-system to overload the existing payment session, rather than create
a brand new one. This allows us to re-use more of the existing logic, and
also feedback into mission control the failures incurred by any user
selected routes.
This commit is contained in:
Olaoluwa Osuntokun 2018-06-06 20:33:55 -07:00
parent 9f183dc08f
commit 0113035f6d
No known key found for this signature in database
GPG Key ID: 964EA263DD637C21
2 changed files with 45 additions and 44 deletions

@ -1,6 +1,7 @@
package routing
import (
"fmt"
"sync"
"time"
@ -71,8 +72,7 @@ type missionControl struct {
// newMissionControl returns a new instance of missionControl.
//
// TODO(roasbeef): persist memory
func newMissionControl(
g *channeldb.ChannelGraph, selfNode *channeldb.LightningNode,
func newMissionControl(g *channeldb.ChannelGraph, selfNode *channeldb.LightningNode,
qb func(*channeldb.ChannelEdgeInfo) lnwire.MilliSatoshi) *missionControl {
return &missionControl{
@ -165,6 +165,9 @@ type paymentSession struct {
bandwidthHints map[uint64]lnwire.MilliSatoshi
mc *missionControl
haveRoutes bool
preBuiltRoutes []*Route
}
// NewPaymentSession creates a new payment session backed by the latest prune
@ -240,6 +243,18 @@ func (m *missionControl) NewPaymentSession(routeHints [][]HopHint,
}, nil
}
// NewPaymentSessionFromRoutes creates a new paymentSession instance that will
// skip all path finding, and will instead utilize a set of pre-built routes.
// This constructor allows callers to specify their own routes which can be
// used for things like channel rebalancing, and swaps.
func (m *missionControl) NewPaymentSessionFromRoutes(routes []*Route) *paymentSession {
return &paymentSession{
haveRoutes: true,
preBuiltRoutes: routes,
mc: m,
}
}
// generateBandwidthHints is a helper function that's utilized the main
// findPath function in order to obtain hints from the lower layer w.r.t to the
// available bandwidth of edges on the network. Currently, we'll only obtain
@ -326,9 +341,25 @@ func (p *paymentSession) ReportChannelFailure(e uint64) {
func (p *paymentSession) RequestRoute(payment *LightningPayment,
height uint32, finalCltvDelta uint16) (*Route, error) {
// First, we'll obtain our current prune view snapshot. This view will
// only ever grow during the duration of this payment session, never
// shrinking.
switch {
// If we have a set of pre-built routes, then we'll just pop off the
// next route from the queue, and use it directly.
case p.haveRoutes && len(p.preBuiltRoutes) > 0:
nextRoute := p.preBuiltRoutes[0]
p.preBuiltRoutes[0] = nil // Set to nil to avoid GC leak.
p.preBuiltRoutes = p.preBuiltRoutes[1:]
return nextRoute, nil
// If we were instantiated with a set of pre-built routes, and we've
// run out, then we'll return a terminal error.
case p.haveRoutes && len(p.preBuiltRoutes) == 0:
return nil, fmt.Errorf("pre-built routes exhausted")
}
// Otherwise we actually need to perform path finding, so we'll obtain
// our current prune view snapshot. This view will only ever grow
// during the duration of this payment session, never shrinking.
pruneView := p.pruneViewSnapshot
log.Debugf("Mission Control session using prune view of %v "+
@ -352,8 +383,9 @@ func (p *paymentSession) RequestRoute(payment *LightningPayment,
// With the next candidate path found, we'll attempt to turn this into
// a route by applying the time-lock and fee requirements.
sourceVertex := Vertex(p.mc.selfNode.PubKeyBytes)
route, err := newRoute(payment.Amount, sourceVertex, path, height,
finalCltvDelta)
route, err := newRoute(
payment.Amount, sourceVertex, path, height, finalCltvDelta,
)
if err != nil {
// TODO(roasbeef): return which edge/vertex didn't work
// out

@ -1532,37 +1532,6 @@ type LightningPayment struct {
// TODO(roasbeef): add e2e message?
}
// PaymentSession imitates paymentSession created from mission control
// and enables SendPayment and SendToRoute to call sendPayment.
type PaymentSession interface {
RequestRoute(payment *LightningPayment, currentHeight uint32,
finalCLTVDelta uint16) (*Route, error)
ReportVertexFailure(Vertex)
ReportChannelFailure(chanID uint64)
}
// sendToRoutePaymentSession implements PaymentSession.
type sendToRoutePaymentSession struct {
currentRouteIndex int
routes []*Route
}
func (s *sendToRoutePaymentSession) RequestRoute(payment *LightningPayment,
currentHeight uint32, finalCLTVDelta uint16) (*Route, error) {
defer func() { s.currentRouteIndex++ }()
if s.currentRouteIndex < len(s.routes) {
return s.routes[s.currentRouteIndex], nil
}
return nil, errors.New("unable to send payment along any of " +
"the given routes")
}
func (s *sendToRoutePaymentSession) ReportVertexFailure(v Vertex) {}
func (s *sendToRoutePaymentSession) ReportChannelFailure(chanID uint64) {}
// SendPayment attempts to send a payment as described within the passed
// LightningPayment. This function is blocking and will return either: when the
// payment is successful, or all candidates routes have been attempted and
@ -1594,9 +1563,9 @@ func (r *ChannelRouter) SendPayment(payment *LightningPayment) ([32]byte, *Route
func (r *ChannelRouter) SendToRoute(routes []*Route,
payment *LightningPayment) ([32]byte, *Route, error) {
paySession := &sendToRoutePaymentSession{
routes: routes,
}
paySession := r.missionControl.NewPaymentSessionFromRoutes(
routes,
)
return r.sendPayment(payment, paySession)
}
@ -1609,7 +1578,7 @@ func (r *ChannelRouter) SendToRoute(routes []*Route,
// within the network to reach the destination. Additionally, the payment
// preimage will also be returned.
func (r *ChannelRouter) sendPayment(payment *LightningPayment,
paySession PaymentSession) ([32]byte, *Route, error) {
paySession *paymentSession) ([32]byte, *Route, error) {
log.Tracef("Dispatching route for lightning payment: %v",
newLogClosure(func() string {
@ -1960,7 +1929,7 @@ func (r *ChannelRouter) sendPayment(payment *LightningPayment,
// pruneVertexFailure will attempt to prune a vertex from the current available
// vertexes of the target payment session in response to an encountered routing
// error.
func pruneVertexFailure(paySession PaymentSession, route *Route,
func pruneVertexFailure(paySession *paymentSession, route *Route,
errSource *btcec.PublicKey, nextNode bool) {
// By default, we'll try to prune the node that actually sent us the
@ -1986,7 +1955,7 @@ func pruneVertexFailure(paySession PaymentSession, route *Route,
// pruneEdgeFailure will attempts to prune an edge from the current available
// edges of the target payment session in response to an encountered routing
// error.
func pruneEdgeFailure(paySession PaymentSession, route *Route,
func pruneEdgeFailure(paySession *paymentSession, route *Route,
errSource *btcec.PublicKey) {
// As this error indicates that the target channel was unable to carry