routing+routerrpc: isolate payment session source from mission control
This commit is contained in:
12 files changed
+308
-191
No files matched your search
+12
-145
@@ -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",
|
||||
|
||||
Reference in new issue
Block a user