Skip to content

Commit bceca88

Browse files
committed
askrene: refactor get_routes ...
We are looking to set the stage for an execution logic that allows for multiple choices of routing algorithms, mainly for experimenting without breaking the default working code. Changelog-None Signed-off-by: Lagrang3 <lagrang3@protonmail.com>
1 parent 7e173e2 commit bceca88

File tree

3 files changed

+172
-121
lines changed

3 files changed

+172
-121
lines changed

plugins/askrene/askrene.c

+7-121
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,9 @@
1818
#include <errno.h>
1919
#include <math.h>
2020
#include <plugins/askrene/askrene.h>
21-
#include <plugins/askrene/explain_failure.h>
2221
#include <plugins/askrene/flow.h>
2322
#include <plugins/askrene/layer.h>
2423
#include <plugins/askrene/mcf.h>
25-
#include <plugins/askrene/refine.h>
2624
#include <plugins/askrene/reserve.h>
2725

2826
/* "spendable" for a channel assumes a single HTLC: for additional HTLCs,
@@ -332,22 +330,6 @@ const char *fmt_flow_full(const tal_t *ctx,
332330
return str;
333331
}
334332

335-
static struct amount_msat linear_flows_cost(struct flow **flows,
336-
struct amount_msat total_amount,
337-
double delay_feefactor)
338-
{
339-
struct amount_msat total = AMOUNT_MSAT(0);
340-
341-
for (size_t i = 0; i < tal_count(flows); i++) {
342-
if (!amount_msat_accumulate(&total,
343-
linear_flow_cost(flows[i],
344-
total_amount,
345-
delay_feefactor)))
346-
abort();
347-
}
348-
return total;
349-
}
350-
351333
static u64 time_delta_ms(struct timerel t)
352334
{
353335
u64 msec = t.ts.tv_sec * 1000 + t.ts.tv_nsec / 1000000;
@@ -376,8 +358,6 @@ static const char *get_routes(const tal_t *ctx,
376358
struct route_query *rq = tal(ctx, struct route_query);
377359
struct flow **flows;
378360
const struct gossmap_node *srcnode, *dstnode;
379-
double delay_feefactor;
380-
u32 mu;
381361
const char *ret;
382362
struct timerel time_delta;
383363
struct timemono time_start = time_mono();
@@ -451,109 +431,15 @@ static const char *get_routes(const tal_t *ctx,
451431
goto fail;
452432
}
453433

454-
delay_feefactor = 1.0/1000000;
455-
456-
/* First up, don't care about fees (well, just enough to tiebreak!) */
457-
mu = 1;
458-
flows = minflow(rq, rq, srcnode, dstnode, amount,
459-
mu, delay_feefactor, single_path);
460-
if (!flows) {
461-
ret = explain_failure(ctx, rq, srcnode, dstnode, amount);
462-
goto fail;
463-
}
464-
465-
/* Too much delay? */
466-
while (finalcltv + flows_worst_delay(flows) > maxdelay) {
467-
delay_feefactor *= 2;
468-
rq_log(tmpctx, rq, LOG_UNUSUAL,
469-
"The worst flow delay is %"PRIu64" (> %i), retrying with delay_feefactor %f...",
470-
flows_worst_delay(flows), maxdelay - finalcltv, delay_feefactor);
471-
flows = minflow(rq, rq, srcnode, dstnode, amount,
472-
mu, delay_feefactor, single_path);
473-
if (!flows || delay_feefactor > 10) {
474-
ret = rq_log(ctx, rq, LOG_UNUSUAL,
475-
"Could not find route without excessive delays");
476-
goto fail;
477-
}
478-
}
479-
480-
/* Too expensive? */
481-
too_expensive:
482-
while (amount_msat_greater(flowset_fee(rq->plugin, flows), maxfee)) {
483-
struct flow **new_flows;
484-
485-
if (mu == 1)
486-
mu = 10;
487-
else
488-
mu += 10;
489-
rq_log(tmpctx, rq, LOG_UNUSUAL,
490-
"The flows had a fee of %s, greater than max of %s, retrying with mu of %u%%...",
491-
fmt_amount_msat(tmpctx, flowset_fee(rq->plugin, flows)),
492-
fmt_amount_msat(tmpctx, maxfee),
493-
mu);
494-
new_flows = minflow(rq, rq, srcnode, dstnode, amount,
495-
mu > 100 ? 100 : mu, delay_feefactor, single_path);
496-
if (!flows || mu >= 100) {
497-
ret = rq_log(ctx, rq, LOG_UNUSUAL,
498-
"Could not find route without excessive cost");
499-
goto fail;
500-
}
501-
502-
/* This is possible, because MCF's linear fees are not the same. */
503-
if (amount_msat_greater(flowset_fee(rq->plugin, new_flows),
504-
flowset_fee(rq->plugin, flows))) {
505-
struct amount_msat old_cost = linear_flows_cost(flows, amount, delay_feefactor);
506-
struct amount_msat new_cost = linear_flows_cost(new_flows, amount, delay_feefactor);
507-
if (amount_msat_greater_eq(new_cost, old_cost)) {
508-
rq_log(tmpctx, rq, LOG_BROKEN, "Old flows cost %s:",
509-
fmt_amount_msat(tmpctx, old_cost));
510-
for (size_t i = 0; i < tal_count(flows); i++) {
511-
rq_log(tmpctx, rq, LOG_BROKEN,
512-
"Flow %zu/%zu: %s (linear cost %s)", i, tal_count(flows),
513-
fmt_flow_full(tmpctx, rq, flows[i]),
514-
fmt_amount_msat(tmpctx, linear_flow_cost(flows[i],
515-
amount,
516-
delay_feefactor)));
517-
}
518-
rq_log(tmpctx, rq, LOG_BROKEN, "Old flows cost %s:",
519-
fmt_amount_msat(tmpctx, new_cost));
520-
for (size_t i = 0; i < tal_count(new_flows); i++) {
521-
rq_log(tmpctx, rq, LOG_BROKEN,
522-
"Flow %zu/%zu: %s (linear cost %s)", i, tal_count(new_flows),
523-
fmt_flow_full(tmpctx, rq, new_flows[i]),
524-
fmt_amount_msat(tmpctx, linear_flow_cost(new_flows[i],
525-
amount,
526-
delay_feefactor)));
527-
}
528-
}
529-
}
530-
tal_free(flows);
531-
flows = new_flows;
532-
}
533-
534-
if (finalcltv + flows_worst_delay(flows) > maxdelay) {
535-
ret = rq_log(ctx, rq, LOG_UNUSUAL,
536-
"Could not find route without excessive cost or delays");
537-
goto fail;
538-
}
539-
540-
/* The above did not take into account the extra funds to pay
541-
* fees, so we try to adjust now. We could re-run MCF if this
542-
* fails, but failure basically never happens where payment is
543-
* still possible */
544-
ret = refine_with_fees_and_limits(ctx, rq, amount, &flows, probability);
545-
if (ret)
434+
/* FIXME: single_path should signal a change in algorithm. */
435+
ret = default_routes(rq, rq, srcnode, dstnode, amount, single_path,
436+
maxfee, finalcltv, maxdelay, &flows, probability);
437+
if (ret) {
546438
goto fail;
547-
548-
/* Again, a tiny corner case: refine step can make us exceed maxfee */
549-
if (amount_msat_greater(flowset_fee(rq->plugin, flows), maxfee)) {
550-
rq_log(tmpctx, rq, LOG_UNUSUAL,
551-
"After final refinement, fee was excessive: retrying");
552-
goto too_expensive;
553439
}
554-
555-
rq_log(tmpctx, rq, LOG_DBG, "Final answer has %zu flows with mu=%u",
556-
tal_count(flows), mu);
440+
assert(tal_count(flows) > 0);
441+
rq_log(tmpctx, rq, LOG_DBG, "Final answer has %zu flows",
442+
tal_count(flows));
557443

558444
/* Convert back into routes, with delay and other information fixed */
559445
*routes = tal_arr(ctx, struct route *, tal_count(flows));

plugins/askrene/mcf.c

+155
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,11 @@
1111
#include <plugins/askrene/algorithm.h>
1212
#include <plugins/askrene/askrene.h>
1313
#include <plugins/askrene/dijkstra.h>
14+
#include <plugins/askrene/explain_failure.h>
1415
#include <plugins/askrene/flow.h>
1516
#include <plugins/askrene/graph.h>
1617
#include <plugins/askrene/mcf.h>
18+
#include <plugins/askrene/refine.h>
1719
#include <plugins/libplugin.h>
1820
#include <stdint.h>
1921

@@ -1080,3 +1082,156 @@ struct flow **minflow(const tal_t *ctx,
10801082
tal_free(working_ctx);
10811083
return NULL;
10821084
}
1085+
1086+
static struct amount_msat linear_flows_cost(struct flow **flows,
1087+
struct amount_msat total_amount,
1088+
double delay_feefactor)
1089+
{
1090+
struct amount_msat total = AMOUNT_MSAT(0);
1091+
1092+
for (size_t i = 0; i < tal_count(flows); i++) {
1093+
if (!amount_msat_accumulate(&total,
1094+
linear_flow_cost(flows[i],
1095+
total_amount,
1096+
delay_feefactor)))
1097+
abort();
1098+
}
1099+
return total;
1100+
}
1101+
1102+
1103+
const char *default_routes(const tal_t *ctx, struct route_query *rq,
1104+
const struct gossmap_node *srcnode,
1105+
const struct gossmap_node *dstnode,
1106+
struct amount_msat amount, bool single_path,
1107+
struct amount_msat maxfee, u32 finalcltv,
1108+
u32 maxdelay, struct flow ***flows,
1109+
double *probability)
1110+
{
1111+
const char *ret;
1112+
double delay_feefactor = 1.0 / 1000000;
1113+
1114+
/* First up, don't care about fees (well, just enough to tiebreak!) */
1115+
u32 mu = 1;
1116+
*flows = minflow(ctx, rq, srcnode, dstnode, amount, mu, delay_feefactor,
1117+
single_path);
1118+
if (!*flows) {
1119+
ret = explain_failure(ctx, rq, srcnode, dstnode, amount);
1120+
goto fail;
1121+
}
1122+
1123+
/* Too much delay? */
1124+
while (finalcltv + flows_worst_delay(*flows) > maxdelay) {
1125+
delay_feefactor *= 2;
1126+
rq_log(tmpctx, rq, LOG_UNUSUAL,
1127+
"The worst flow delay is %" PRIu64
1128+
" (> %i), retrying with delay_feefactor %f...",
1129+
flows_worst_delay(*flows), maxdelay - finalcltv,
1130+
delay_feefactor);
1131+
*flows = minflow(ctx, rq, srcnode, dstnode, amount, mu,
1132+
delay_feefactor, single_path);
1133+
if (!*flows || delay_feefactor > 10) {
1134+
ret = rq_log(
1135+
ctx, rq, LOG_UNUSUAL,
1136+
"Could not find route without excessive delays");
1137+
goto fail;
1138+
}
1139+
}
1140+
1141+
/* Too expensive? */
1142+
too_expensive:
1143+
while (amount_msat_greater(flowset_fee(rq->plugin, *flows), maxfee)) {
1144+
struct flow **new_flows;
1145+
1146+
if (mu == 1)
1147+
mu = 10;
1148+
else
1149+
mu += 10;
1150+
rq_log(tmpctx, rq, LOG_UNUSUAL,
1151+
"The flows had a fee of %s, greater than max of %s, "
1152+
"retrying with mu of %u%%...",
1153+
fmt_amount_msat(tmpctx, flowset_fee(rq->plugin, *flows)),
1154+
fmt_amount_msat(tmpctx, maxfee), mu);
1155+
new_flows =
1156+
minflow(ctx, rq, srcnode, dstnode, amount,
1157+
mu > 100 ? 100 : mu, delay_feefactor, single_path);
1158+
if (!*flows || mu >= 100) {
1159+
ret = rq_log(
1160+
ctx, rq, LOG_UNUSUAL,
1161+
"Could not find route without excessive cost");
1162+
goto fail;
1163+
}
1164+
1165+
/* This is possible, because MCF's linear fees are not the same.
1166+
*/
1167+
if (amount_msat_greater(flowset_fee(rq->plugin, new_flows),
1168+
flowset_fee(rq->plugin, *flows))) {
1169+
struct amount_msat old_cost =
1170+
linear_flows_cost(*flows, amount, delay_feefactor);
1171+
struct amount_msat new_cost = linear_flows_cost(
1172+
new_flows, amount, delay_feefactor);
1173+
if (amount_msat_greater_eq(new_cost, old_cost)) {
1174+
rq_log(tmpctx, rq, LOG_BROKEN,
1175+
"Old flows cost %s:",
1176+
fmt_amount_msat(tmpctx, old_cost));
1177+
for (size_t i = 0; i < tal_count(*flows); i++) {
1178+
rq_log(
1179+
tmpctx, rq, LOG_BROKEN,
1180+
"Flow %zu/%zu: %s (linear cost %s)",
1181+
i, tal_count(*flows),
1182+
fmt_flow_full(tmpctx, rq, *flows[i]),
1183+
fmt_amount_msat(
1184+
tmpctx, linear_flow_cost(
1185+
*flows[i], amount,
1186+
delay_feefactor)));
1187+
}
1188+
rq_log(tmpctx, rq, LOG_BROKEN,
1189+
"Old flows cost %s:",
1190+
fmt_amount_msat(tmpctx, new_cost));
1191+
for (size_t i = 0; i < tal_count(new_flows);
1192+
i++) {
1193+
rq_log(
1194+
tmpctx, rq, LOG_BROKEN,
1195+
"Flow %zu/%zu: %s (linear cost %s)",
1196+
i, tal_count(new_flows),
1197+
fmt_flow_full(tmpctx, rq,
1198+
new_flows[i]),
1199+
fmt_amount_msat(
1200+
tmpctx,
1201+
linear_flow_cost(
1202+
new_flows[i], amount,
1203+
delay_feefactor)));
1204+
}
1205+
}
1206+
}
1207+
tal_free(*flows);
1208+
*flows = new_flows;
1209+
}
1210+
1211+
if (finalcltv + flows_worst_delay(*flows) > maxdelay) {
1212+
ret = rq_log(
1213+
ctx, rq, LOG_UNUSUAL,
1214+
"Could not find route without excessive cost or delays");
1215+
goto fail;
1216+
}
1217+
1218+
/* The above did not take into account the extra funds to pay
1219+
* fees, so we try to adjust now. We could re-run MCF if this
1220+
* fails, but failure basically never happens where payment is
1221+
* still possible */
1222+
ret = refine_with_fees_and_limits(ctx, rq, amount, flows, probability);
1223+
if (ret)
1224+
goto fail;
1225+
1226+
/* Again, a tiny corner case: refine step can make us exceed maxfee */
1227+
if (amount_msat_greater(flowset_fee(rq->plugin, *flows), maxfee)) {
1228+
rq_log(tmpctx, rq, LOG_UNUSUAL,
1229+
"After final refinement, fee was excessive: retrying");
1230+
goto too_expensive;
1231+
}
1232+
1233+
return NULL;
1234+
fail:
1235+
assert(ret != NULL);
1236+
return ret;
1237+
}

plugins/askrene/mcf.h

+10
Original file line numberDiff line numberDiff line change
@@ -40,4 +40,14 @@ struct amount_msat linear_flow_cost(const struct flow *flow,
4040
struct amount_msat total_amount,
4141
double delay_feefactor);
4242

43+
/* A wrapper to the min. cost flow solver that actually takes into consideration
44+
* the extra msats per channel needed to pay for fees. */
45+
const char *default_routes(const tal_t *ctx, struct route_query *rq,
46+
const struct gossmap_node *srcnode,
47+
const struct gossmap_node *dstnode,
48+
struct amount_msat amount, bool single_path,
49+
struct amount_msat maxfee, u32 finalcltv,
50+
u32 maxdelay, struct flow ***flows,
51+
double *probability);
52+
4353
#endif /* LIGHTNING_PLUGINS_ASKRENE_MCF_H */

0 commit comments

Comments
 (0)