routing+routerrpc: isolate payment session source from mission control

This commit is contained in:
Joost Jager committed 2019-07-13 22:38:19 +02:00
1 parent cf3dd3fb94
commit 37e2751695
12 files changed
+308 -191

No files matched your search

+12 -145
View File
@@ -5,12 +5,10 @@ import (
"sync"
"time"
"github.com/btcsuite/btcd/btcec"
"github.com/coreos/bbolt"
"github.com/lightningnetwork/lnd/channeldb"
"github.com/lightningnetwork/lnd/lnwire"
"github.com/lightningnetwork/lnd/routing/route"
"github.com/lightningnetwork/lnd/zpay32"
)
const (
@@ -32,12 +30,6 @@ const (
type MissionControl struct {
history map[route.Vertex]*nodeHistory
graph *channeldb.ChannelGraph
selfNode *channeldb.LightningNode
queryBandwidth func(*channeldb.ChannelEdgeInfo) lnwire.MilliSatoshi
// now is expected to return the current time. It is supplied as an
// external function to enable deterministic unit tests.
now func() time.Time
@@ -52,10 +44,6 @@ type MissionControl struct {
// TODO(roasbeef): also add favorable metrics for nodes
}
// A compile time assertion to ensure MissionControl meets the
// PaymentSessionSource interface.
var _ PaymentSessionSource = (*MissionControl)(nil)
// MissionControlConfig defines parameters that control mission control
// behaviour.
type MissionControlConfig struct {
@@ -63,16 +51,6 @@ type MissionControlConfig struct {
// channel is back at 50% probability.
PenaltyHalfLife time.Duration
// PaymentAttemptPenalty is the virtual cost in path finding weight
// units of executing a payment attempt that fails. It is used to trade
// off potentially better routes against their probability of
// succeeding.
PaymentAttemptPenalty lnwire.MilliSatoshi
// MinProbability defines the minimum success probability of the
// returned route.
MinRouteProbability float64
// AprioriHopProbability is the assumed success probability of a hop in
// a route when no other information is available.
AprioriHopProbability float64
@@ -143,126 +121,15 @@ type MissionControlChannelSnapshot struct {
}
// NewMissionControl returns a new instance of missionControl.
//
// TODO(roasbeef): persist memory
func NewMissionControl(g *channeldb.ChannelGraph, selfNode *channeldb.LightningNode,
qb func(*channeldb.ChannelEdgeInfo) lnwire.MilliSatoshi,
cfg *MissionControlConfig) *MissionControl {
func NewMissionControl(cfg *MissionControlConfig) *MissionControl {
log.Debugf("Instantiating mission control with config: "+
"PenaltyHalfLife=%v, PaymentAttemptPenalty=%v, "+
"MinRouteProbability=%v, AprioriHopProbability=%v",
cfg.PenaltyHalfLife,
int64(cfg.PaymentAttemptPenalty.ToSatoshis()),
cfg.MinRouteProbability, cfg.AprioriHopProbability)
"PenaltyHalfLife=%v, AprioriHopProbability=%v",
cfg.PenaltyHalfLife, cfg.AprioriHopProbability)
return &MissionControl{
history: make(map[route.Vertex]*nodeHistory),
selfNode: selfNode,
queryBandwidth: qb,
graph: g,
now: time.Now,
cfg: cfg,
}
}
// NewPaymentSession creates a new payment session backed by the latest prune
// view from Mission Control. An optional set of routing hints can be provided
// in order to populate additional edges to explore when finding a path to the
// payment's destination.
func (m *MissionControl) NewPaymentSession(routeHints [][]zpay32.HopHint,
target route.Vertex) (PaymentSession, error) {
edges := make(map[route.Vertex][]*channeldb.ChannelEdgePolicy)
// Traverse through all of the available hop hints and include them in
// our edges map, indexed by the public key of the channel's starting
// node.
for _, routeHint := range routeHints {
// If multiple hop hints are provided within a single route
// hint, we'll assume they must be chained together and sorted
// in forward order in order to reach the target successfully.
for i, hopHint := range routeHint {
// In order to determine the end node of this hint,
// we'll need to look at the next hint's start node. If
// we've reached the end of the hints list, we can
// assume we've reached the destination.
endNode := &channeldb.LightningNode{}
if i != len(routeHint)-1 {
endNode.AddPubKey(routeHint[i+1].NodeID)
} else {
targetPubKey, err := btcec.ParsePubKey(
target[:], btcec.S256(),
)
if err != nil {
return nil, err
}
endNode.AddPubKey(targetPubKey)
}
// Finally, create the channel edge from the hop hint
// and add it to list of edges corresponding to the node
// at the start of the channel.
edge := &channeldb.ChannelEdgePolicy{
Node: endNode,
ChannelID: hopHint.ChannelID,
FeeBaseMSat: lnwire.MilliSatoshi(
hopHint.FeeBaseMSat,
),
FeeProportionalMillionths: lnwire.MilliSatoshi(
hopHint.FeeProportionalMillionths,
),
TimeLockDelta: hopHint.CLTVExpiryDelta,
}
v := route.NewVertex(hopHint.NodeID)
edges[v] = append(edges[v], edge)
}
}
// We'll also obtain a set of bandwidthHints from the lower layer for
// each of our outbound channels. This will allow the path finding to
// skip any links that aren't active or just don't have enough
// bandwidth to carry the payment.
sourceNode, err := m.graph.SourceNode()
if err != nil {
return nil, err
}
bandwidthHints, err := generateBandwidthHints(
sourceNode, m.queryBandwidth,
)
if err != nil {
return nil, err
}
return &paymentSession{
additionalEdges: edges,
bandwidthHints: bandwidthHints,
errFailedPolicyChans: make(map[nodeChannel]struct{}),
mc: m,
pathFinder: findPath,
}, nil
}
// NewPaymentSessionForRoute creates a new paymentSession instance that is just
// used for failure reporting to missioncontrol.
func (m *MissionControl) NewPaymentSessionForRoute(preBuiltRoute *route.Route) PaymentSession {
return &paymentSession{
errFailedPolicyChans: make(map[nodeChannel]struct{}),
mc: m,
preBuiltRoute: preBuiltRoute,
}
}
// NewPaymentSessionEmpty creates a new paymentSession instance that is empty,
// and will be exhausted immediately. Used for failure reporting to
// missioncontrol for resumed payment we don't want to make more attempts for.
func (m *MissionControl) NewPaymentSessionEmpty() PaymentSession {
return &paymentSession{
errFailedPolicyChans: make(map[nodeChannel]struct{}),
mc: m,
preBuiltRoute: &route.Route{},
preBuiltRouteTried: true,
history: make(map[route.Vertex]*nodeHistory),
now: time.Now,
cfg: cfg,
}
}
@@ -312,9 +179,9 @@ func (m *MissionControl) ResetHistory() {
log.Debugf("Mission control history cleared")
}
// getEdgeProbability is expected to return the success probability of a payment
// GetEdgeProbability is expected to return the success probability of a payment
// from fromNode along edge.
func (m *MissionControl) getEdgeProbability(fromNode route.Vertex,
func (m *MissionControl) GetEdgeProbability(fromNode route.Vertex,
edge EdgeLocator, amt lnwire.MilliSatoshi) float64 {
m.Lock()
@@ -391,8 +258,8 @@ func (m *MissionControl) createHistoryIfNotExists(vertex route.Vertex) *nodeHist
return node
}
// reportVertexFailure reports a node level failure.
func (m *MissionControl) reportVertexFailure(v route.Vertex) {
// ReportVertexFailure reports a node level failure.
func (m *MissionControl) ReportVertexFailure(v route.Vertex) {
log.Debugf("Reporting vertex %v failure to Mission Control", v)
now := m.now()
@@ -404,10 +271,10 @@ func (m *MissionControl) reportVertexFailure(v route.Vertex) {
history.lastFail = &now
}
// reportEdgeFailure reports a channel level failure.
// ReportEdgeFailure reports a channel level failure.
//
// TODO(roasbeef): also add value attempted to send and capacity of channel
func (m *MissionControl) reportEdgeFailure(failedEdge edge,
func (m *MissionControl) ReportEdgeFailure(failedEdge edge,
minPenalizeAmt lnwire.MilliSatoshi) {
log.Debugf("Reporting channel %v failure to Mission Control",