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 }