github.com/decred/dcrlnd@v0.7.6/routing/payment_session_source.go (about)

     1  package routing
     2  
     3  import (
     4  	"github.com/decred/dcrd/dcrec/secp256k1/v4"
     5  	"github.com/decred/dcrlnd/channeldb"
     6  	"github.com/decred/dcrlnd/lnwire"
     7  	"github.com/decred/dcrlnd/routing/route"
     8  	"github.com/decred/dcrlnd/zpay32"
     9  )
    10  
    11  // A compile time assertion to ensure MissionControl meets the
    12  // PaymentSessionSource interface.
    13  var _ PaymentSessionSource = (*SessionSource)(nil)
    14  
    15  // SessionSource defines a source for the router to retrieve new payment
    16  // sessions.
    17  type SessionSource struct {
    18  	// Graph is the channel graph that will be used to gather metrics from
    19  	// and also to carry out path finding queries.
    20  	Graph *channeldb.ChannelGraph
    21  
    22  	// SourceNode is the graph's source node.
    23  	SourceNode *channeldb.LightningNode
    24  
    25  	// GetLink is a method that allows querying the lower link layer
    26  	// to determine the up to date available bandwidth at a prospective link
    27  	// to be traversed. If the link isn't available, then a value of zero
    28  	// should be returned. Otherwise, the current up to date knowledge of
    29  	// the available bandwidth of the link should be returned.
    30  	GetLink getLinkQuery
    31  
    32  	// MissionControl is a shared memory of sorts that executions of payment
    33  	// path finding use in order to remember which vertexes/edges were
    34  	// pruned from prior attempts. During payment execution, errors sent by
    35  	// nodes are mapped into a vertex or edge to be pruned. Each run will
    36  	// then take into account this set of pruned vertexes/edges to reduce
    37  	// route failure and pass on graph information gained to the next
    38  	// execution.
    39  	MissionControl MissionController
    40  
    41  	// PathFindingConfig defines global parameters that control the
    42  	// trade-off in path finding between fees and probabiity.
    43  	PathFindingConfig PathFindingConfig
    44  }
    45  
    46  // getRoutingGraph returns a routing graph and a clean-up function for
    47  // pathfinding.
    48  func (m *SessionSource) getRoutingGraph() (routingGraph, func(), error) {
    49  	routingTx, err := NewCachedGraph(m.SourceNode, m.Graph)
    50  	if err != nil {
    51  		return nil, nil, err
    52  	}
    53  	return routingTx, func() {
    54  		err := routingTx.close()
    55  		if err != nil {
    56  			log.Errorf("Error closing db tx: %v", err)
    57  		}
    58  	}, nil
    59  }
    60  
    61  // NewPaymentSession creates a new payment session backed by the latest prune
    62  // view from Mission Control. An optional set of routing hints can be provided
    63  // in order to populate additional edges to explore when finding a path to the
    64  // payment's destination.
    65  func (m *SessionSource) NewPaymentSession(p *LightningPayment) (
    66  	PaymentSession, error) {
    67  
    68  	getBandwidthHints := func(graph routingGraph) (bandwidthHints, error) {
    69  		return newBandwidthManager(
    70  			graph, m.SourceNode.PubKeyBytes, m.GetLink,
    71  		)
    72  	}
    73  
    74  	session, err := newPaymentSession(
    75  		p, getBandwidthHints, m.getRoutingGraph,
    76  		m.MissionControl, m.PathFindingConfig,
    77  	)
    78  	if err != nil {
    79  		return nil, err
    80  	}
    81  
    82  	return session, nil
    83  }
    84  
    85  // NewPaymentSessionEmpty creates a new paymentSession instance that is empty,
    86  // and will be exhausted immediately. Used for failure reporting to
    87  // missioncontrol for resumed payment we don't want to make more attempts for.
    88  func (m *SessionSource) NewPaymentSessionEmpty() PaymentSession {
    89  	return &paymentSession{
    90  		empty: true,
    91  	}
    92  }
    93  
    94  // RouteHintsToEdges converts a list of invoice route hints to an edge map that
    95  // can be passed into pathfinding.
    96  func RouteHintsToEdges(routeHints [][]zpay32.HopHint, target route.Vertex) (
    97  	map[route.Vertex][]*channeldb.CachedEdgePolicy, error) {
    98  
    99  	edges := make(map[route.Vertex][]*channeldb.CachedEdgePolicy)
   100  
   101  	// Traverse through all of the available hop hints and include them in
   102  	// our edges map, indexed by the public key of the channel's starting
   103  	// node.
   104  	for _, routeHint := range routeHints {
   105  		// If multiple hop hints are provided within a single route
   106  		// hint, we'll assume they must be chained together and sorted
   107  		// in forward order in order to reach the target successfully.
   108  		for i, hopHint := range routeHint {
   109  			// In order to determine the end node of this hint,
   110  			// we'll need to look at the next hint's start node. If
   111  			// we've reached the end of the hints list, we can
   112  			// assume we've reached the destination.
   113  			endNode := &channeldb.LightningNode{}
   114  			if i != len(routeHint)-1 {
   115  				endNode.AddPubKey(routeHint[i+1].NodeID)
   116  			} else {
   117  				targetPubKey, err := secp256k1.ParsePubKey(
   118  					target[:],
   119  				)
   120  				if err != nil {
   121  					return nil, err
   122  				}
   123  				endNode.AddPubKey(targetPubKey)
   124  			}
   125  
   126  			// Finally, create the channel edge from the hop hint
   127  			// and add it to list of edges corresponding to the node
   128  			// at the start of the channel.
   129  			edge := &channeldb.CachedEdgePolicy{
   130  				ToNodePubKey: func() route.Vertex {
   131  					return endNode.PubKeyBytes
   132  				},
   133  				ToNodeFeatures: lnwire.EmptyFeatureVector(),
   134  				ChannelID:      hopHint.ChannelID,
   135  				FeeBaseMAtoms: lnwire.MilliAtom(
   136  					hopHint.FeeBaseMAtoms,
   137  				),
   138  				FeeProportionalMillionths: lnwire.MilliAtom(
   139  					hopHint.FeeProportionalMillionths,
   140  				),
   141  				TimeLockDelta: hopHint.CLTVExpiryDelta,
   142  			}
   143  
   144  			v := route.NewVertex(hopHint.NodeID)
   145  			edges[v] = append(edges[v], edge)
   146  		}
   147  	}
   148  
   149  	return edges, nil
   150  }