Skip to content

Commit 2d94d22

Browse files
committed
blinded route request
1 parent c8a54d0 commit 2d94d22

File tree

3 files changed

+58
-1
lines changed

3 files changed

+58
-1
lines changed

eclair-core/src/main/scala/fr/acinq/eclair/router/Graph.scala

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -434,6 +434,36 @@ object Graph {
434434
wr: MessageWeightRatios): Option[Seq[GraphEdge]] =
435435
dijkstraShortestPath(g, sourceNode, targetNode, ignoredEdges = Set.empty, ignoredVertices, extraEdges = Set.empty, MessagePathWeight.zero, boundaries, Features(Features.OnionMessages -> FeatureSupport.Mandatory), currentBlockHeight, wr, includeLocalChannelCost = true)
436436

437+
/**
438+
* Find non-overlapping (no vertices shared) payment paths that support route blinding
439+
*
440+
* @param pathsToFind Number of paths to find. We may return fewer paths if we couldn't find more non-overlapping ones.
441+
*/
442+
def routeBlindingPaths(graph: DirectedGraph,
443+
sourceNode: PublicKey,
444+
targetNode: PublicKey,
445+
amount: MilliSatoshi,
446+
ignoredEdges: Set[ChannelDesc],
447+
ignoredVertices: Set[PublicKey],
448+
pathsToFind: Int,
449+
wr: WeightRatios[PaymentPathWeight],
450+
currentBlockHeight: BlockHeight,
451+
boundaries: PaymentPathWeight => Boolean): Seq[WeightedPath] = {
452+
val paths = new mutable.ArrayBuffer[WeightedPath](pathsToFind)
453+
val verticesToIgnore = new mutable.HashSet[PublicKey]()
454+
verticesToIgnore.addAll(ignoredVertices)
455+
for (_ <- 1 to pathsToFind) {
456+
dijkstraShortestPath(graph, sourceNode, targetNode, ignoredEdges, verticesToIgnore.toSet, extraEdges = Set.empty, PaymentPathWeight(amount), boundaries, Features(Features.RouteBlinding -> FeatureSupport.Mandatory), currentBlockHeight, wr, includeLocalChannelCost = true) match {
457+
case Some(path) =>
458+
val weight = pathWeight(sourceNode, path, amount, currentBlockHeight, wr, includeLocalChannelCost = true)
459+
paths += WeightedPath(path, weight)
460+
verticesToIgnore.addAll(path.drop(1).map(_.desc.a))
461+
case None => return paths.toSeq
462+
}
463+
}
464+
paths.toSeq
465+
}
466+
437467
/**
438468
* Calculate the minimum amount that the start node needs to receive to be able to forward @amountWithFees to the end
439469
* node.

eclair-core/src/main/scala/fr/acinq/eclair/router/RouteCalculation.scala

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616

1717
package fr.acinq.eclair.router
1818

19-
import akka.actor.{ActorContext, ActorRef, Status}
19+
import akka.actor.{ActorContext, ActorRef}
2020
import akka.event.DiagnosticLoggingAdapter
2121
import com.softwaremill.quicklens.ModifyPimp
2222
import fr.acinq.bitcoin.scalacompat.Crypto.PublicKey
@@ -229,6 +229,22 @@ object RouteCalculation {
229229
}
230230
}
231231

232+
def handleBlindedRouteRequest(d: Data, currentBlockHeight: BlockHeight, r: BlindedRouteRequest)(implicit log: DiagnosticLoggingAdapter): Data = {
233+
val maxFee = r.routeParams.getMaxFee(r.amount)
234+
235+
val boundaries: PaymentPathWeight => Boolean = { weight =>
236+
weight.amount - r.amount <= maxFee &&
237+
weight.length <= r.routeParams.boundaries.maxRouteLength &&
238+
weight.length <= ROUTE_MAX_LENGTH &&
239+
weight.cltv <= r.routeParams.boundaries.maxCltv
240+
}
241+
242+
val routes = Graph.routeBlindingPaths(d.graphWithBalances.graph, r.source, r.target, r.amount, r.ignore.channels, r.ignore.nodes, r.pathsToFind, r.routeParams.heuristics, currentBlockHeight, boundaries)
243+
// TODO: check if routes is empty
244+
r.replyTo ! RouteResponse(routes.map(route => Route(r.amount, route.path.map(graphEdgeToHop), None)))
245+
d
246+
}
247+
232248
def handleMessageRouteRequest(d: Data, currentBlockHeight: BlockHeight, r: MessageRouteRequest, routeParams: MessageRouteParams)(implicit log: DiagnosticLoggingAdapter): Data = {
233249
val boundaries: MessagePathWeight => Boolean = { weight =>
234250
weight.length <= routeParams.maxRouteLength && weight.length <= ROUTE_MAX_LENGTH

eclair-core/src/main/scala/fr/acinq/eclair/router/Router.scala

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -241,6 +241,9 @@ class Router(val nodeParams: NodeParams, watcher: typed.ActorRef[ZmqWatcher.Comm
241241
case Event(r: RouteRequest, d) =>
242242
stay() using RouteCalculation.handleRouteRequest(d, nodeParams.currentBlockHeight, r)
243243

244+
case Event(r: BlindedRouteRequest, d) =>
245+
stay() using RouteCalculation.handleBlindedRouteRequest(d, nodeParams.currentBlockHeight, r)
246+
244247
case Event(r: MessageRouteRequest, d) =>
245248
stay() using RouteCalculation.handleMessageRouteRequest(d, nodeParams.currentBlockHeight, r, nodeParams.routerConf.messageRouteParams)
246249

@@ -616,6 +619,14 @@ object Router {
616619
pendingPayments: Seq[Route] = Nil,
617620
paymentContext: Option[PaymentContext] = None)
618621

622+
case class BlindedRouteRequest(replyTo: typed.ActorRef[PaymentRouteResponse],
623+
source: PublicKey,
624+
target: PublicKey,
625+
amount: MilliSatoshi,
626+
routeParams: RouteParams,
627+
pathsToFind: Int,
628+
ignore: Ignore = Ignore.empty)
629+
619630
case class FinalizeRoute(replyTo: typed.ActorRef[PaymentRouteResponse],
620631
route: PredefinedRoute,
621632
extraEdges: Seq[ExtraEdge] = Nil,

0 commit comments

Comments
 (0)