From 38f9c01a711ed279d777585fbf14a0d3ac4f0bf8 Mon Sep 17 00:00:00 2001 From: Rene Pickhardt Date: Fri, 24 Nov 2023 15:46:32 +0100 Subject: [PATCH] PoC max expected value splitting * removed Random amount assigning in payment allocation of `split` * added rough (maybe not even compilable code) that estimates the max expected value * thanks for two hours with @stefanwouldgo to discuss the scala way of achieving things --- .../eclair/router/RouteCalculation.scala | 21 ++++++++----------- 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/router/RouteCalculation.scala b/eclair-core/src/main/scala/fr/acinq/eclair/router/RouteCalculation.scala index b0b1e4c4c9..3fbcba5137 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/router/RouteCalculation.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/router/RouteCalculation.scala @@ -446,24 +446,21 @@ object RouteCalculation { // this route doesn't have enough capacity left: we remove it and continue. split(amount, paths, usedCapacity, routeParams, selectedRoutes) } else { - val route = if (routeParams.randomize) { - // randomly choose the amount to be between 20% and 100% of the available capacity. - val randomizedAmount = candidate.amount * ((20d + Random.nextInt(81)) / 100) - if (randomizedAmount < routeParams.mpp.minPartAmount) { - candidate.copy(amount = routeParams.mpp.minPartAmount.min(amount)) - } else { - candidate.copy(amount = randomizedAmount.min(amount)) - } - } else { - candidate.copy(amount = candidate.amount.min(amount)) - } + val route = candidate.copy(amount = (1 to 100).map(candidate.amount*_/100).foreach(i => (expectedValue(candidate, i, usedCapacity), i)).maxBy(_._1)._2.min(amount) updateUsedCapacity(route, usedCapacity) // NB: we re-enqueue the current path, it may still have capacity for a second HTLC. split(amount - route.amount, paths.enqueue(current), usedCapacity, routeParams, route +: selectedRoutes) } } } - + private def expectedValue(route: Route, Integer testAmount, usedCapacity: mutable.Map[ShortChannelId, MilliSatoshi]): Float{ + route.path.drop(1).foldLeft(testAmount){ case (ev,edge) => + val inflight = usedCapacity.getOrElse(edge.desc.shortChannelId, 0 msat)) + val cap = edge.desc.capacity + (cap + 1.0 - inflight - testAmount) / (cap + 1 - inflight) * ev + } + } + /** Compute the maximum amount that we can send through the given route. */ private def computeRouteMaxAmount(route: Seq[GraphEdge], usedCapacity: mutable.Map[ShortChannelId, MilliSatoshi]): Route = { val firstHopMaxAmount = route.head.maxHtlcAmount(usedCapacity.getOrElse(route.head.desc.shortChannelId, 0 msat))