Skip to content

Commit 3b53820

Browse files
committed
askrene: add algorithm for single path routing
Changelog-Added: askrene: an optimal single-path solver has been added, it can be called using the developer option --dev_algorithm=single-path or by adding the layer "auto.no_mpp_support" Signed-off-by: Lagrang3 <[email protected]>
1 parent 3db2ce4 commit 3b53820

File tree

3 files changed

+77
-50
lines changed

3 files changed

+77
-50
lines changed

plugins/askrene/askrene.c

Lines changed: 26 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -332,7 +332,11 @@ const char *fmt_flow_full(const tal_t *ctx,
332332
}
333333

334334
enum algorithm {
335+
/* Min. Cost Flow by successive shortests paths. */
335336
ALGO_DEFAULT,
337+
/* Algorithm that finds the optimal routing solution constrained to a
338+
* single path. */
339+
ALGO_SINGLE_PATH,
336340
};
337341

338342
static struct command_result *
@@ -343,6 +347,8 @@ param_algorithm(struct command *cmd, const char *name, const char *buffer,
343347
*algo = tal(cmd, enum algorithm);
344348
if (streq(algo_str, "default"))
345349
**algo = ALGO_DEFAULT;
350+
else if (streq(algo_str, "single-path"))
351+
**algo = ALGO_SINGLE_PATH;
346352
else
347353
return command_fail_badparam(cmd, name, buffer, tok,
348354
"unknown algorithm");
@@ -581,15 +587,29 @@ static struct command_result *do_getroutes(struct command *cmd,
581587
goto fail;
582588
}
583589

590+
/* auto.no_mpp_support layer overrides any choice of algorithm. */
591+
if (have_layer(info->layers, "auto.no_mpp_support") &&
592+
*info->dev_algo != ALGO_SINGLE_PATH) {
593+
*info->dev_algo = ALGO_SINGLE_PATH;
594+
rq_log(tmpctx, rq, LOG_DBG,
595+
"Layer no_mpp_support is active we switch to a "
596+
"single path algorithm.");
597+
}
598+
584599
/* Compute the routes. At this point we might select between multiple
585600
* algorithms. Right now there is only one algorithm available. */
586601
struct timemono time_start = time_mono();
587-
assert(*info->dev_algo == ALGO_DEFAULT);
588-
err = default_routes(rq, rq, srcnode, dstnode, *info->amount,
589-
/* only one path? = */
590-
have_layer(info->layers, "auto.no_mpp_support"),
591-
*info->maxfee, *info->finalcltv, *info->maxdelay,
592-
&flows, &probability);
602+
if (*info->dev_algo == ALGO_SINGLE_PATH){
603+
err = single_path_routes(
604+
rq, rq, srcnode, dstnode, *info->amount,
605+
*info->maxfee, *info->finalcltv, *info->maxdelay, &flows,
606+
&probability);
607+
} else {
608+
assert(*info->dev_algo == ALGO_DEFAULT);
609+
err = default_routes(rq, rq, srcnode, dstnode, *info->amount,
610+
*info->maxfee, *info->finalcltv,
611+
*info->maxdelay, &flows, &probability);
612+
}
593613
struct timerel time_delta = timemono_between(time_mono(), time_start);
594614

595615
/* log the time of computation */

plugins/askrene/mcf.c

Lines changed: 40 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -952,8 +952,7 @@ struct flow **minflow(const tal_t *ctx,
952952
const struct gossmap_node *target,
953953
struct amount_msat amount,
954954
u32 mu,
955-
double delay_feefactor,
956-
bool single_part)
955+
double delay_feefactor)
957956
{
958957
struct flow **flow_paths;
959958
/* We allocate everything off this, and free it at the end,
@@ -1044,31 +1043,6 @@ struct flow **minflow(const tal_t *ctx,
10441043
goto fail;
10451044
}
10461045
tal_free(working_ctx);
1047-
1048-
/* This is dumb, but if you don't support MPP you don't deserve any
1049-
* better. Pile it into the largest part if not already. */
1050-
if (single_part) {
1051-
struct flow *best = flow_paths[0];
1052-
for (size_t i = 1; i < tal_count(flow_paths); i++) {
1053-
if (amount_msat_greater(flow_paths[i]->delivers, best->delivers))
1054-
best = flow_paths[i];
1055-
}
1056-
for (size_t i = 0; i < tal_count(flow_paths); i++) {
1057-
if (flow_paths[i] == best)
1058-
continue;
1059-
if (!amount_msat_accumulate(&best->delivers,
1060-
flow_paths[i]->delivers)) {
1061-
rq_log(tmpctx, rq, LOG_BROKEN,
1062-
"%s: failed to extract accumulate flow paths %s+%s",
1063-
__func__,
1064-
fmt_amount_msat(tmpctx, best->delivers),
1065-
fmt_amount_msat(tmpctx, flow_paths[i]->delivers));
1066-
goto fail;
1067-
}
1068-
}
1069-
flow_paths[0] = best;
1070-
tal_resize(&flow_paths, 1);
1071-
}
10721046
return flow_paths;
10731047

10741048
fail:
@@ -1273,13 +1247,16 @@ struct flow **single_path_flow(const tal_t *ctx, const struct route_query *rq,
12731247
return NULL;
12741248
}
12751249

1276-
const char *default_routes(const tal_t *ctx, struct route_query *rq,
1277-
const struct gossmap_node *srcnode,
1278-
const struct gossmap_node *dstnode,
1279-
struct amount_msat amount, bool single_path,
1280-
struct amount_msat maxfee, u32 finalcltv,
1281-
u32 maxdelay, struct flow ***flows,
1282-
double *probability)
1250+
static const char *
1251+
linear_routes(const tal_t *ctx, struct route_query *rq,
1252+
const struct gossmap_node *srcnode,
1253+
const struct gossmap_node *dstnode, struct amount_msat amount,
1254+
struct amount_msat maxfee, u32 finalcltv, u32 maxdelay,
1255+
struct flow ***flows, double *probability,
1256+
struct flow **(*solver)(const tal_t *, const struct route_query *,
1257+
const struct gossmap_node *,
1258+
const struct gossmap_node *,
1259+
struct amount_msat, u32, double))
12831260
{
12841261
*flows = NULL;
12851262
const char *ret;
@@ -1288,8 +1265,7 @@ const char *default_routes(const tal_t *ctx, struct route_query *rq,
12881265
/* First up, don't care about fees (well, just enough to tiebreak!) */
12891266
u32 mu = 1;
12901267
tal_free(*flows);
1291-
*flows = minflow(ctx, rq, srcnode, dstnode, amount, mu, delay_feefactor,
1292-
single_path);
1268+
*flows = solver(ctx, rq, srcnode, dstnode, amount, mu, delay_feefactor);
12931269
if (!*flows) {
12941270
ret = explain_failure(ctx, rq, srcnode, dstnode, amount);
12951271
goto fail;
@@ -1304,8 +1280,8 @@ const char *default_routes(const tal_t *ctx, struct route_query *rq,
13041280
flows_worst_delay(*flows), maxdelay - finalcltv,
13051281
delay_feefactor);
13061282
tal_free(*flows);
1307-
*flows = minflow(ctx, rq, srcnode, dstnode, amount, mu,
1308-
delay_feefactor, single_path);
1283+
*flows = solver(ctx, rq, srcnode, dstnode, amount, mu,
1284+
delay_feefactor);
13091285
if (!*flows || delay_feefactor > 10) {
13101286
ret = rq_log(
13111287
ctx, rq, LOG_UNUSUAL,
@@ -1328,9 +1304,8 @@ const char *default_routes(const tal_t *ctx, struct route_query *rq,
13281304
"retrying with mu of %u%%...",
13291305
fmt_amount_msat(tmpctx, flowset_fee(rq->plugin, *flows)),
13301306
fmt_amount_msat(tmpctx, maxfee), mu);
1331-
new_flows =
1332-
minflow(ctx, rq, srcnode, dstnode, amount,
1333-
mu > 100 ? 100 : mu, delay_feefactor, single_path);
1307+
new_flows = solver(ctx, rq, srcnode, dstnode, amount,
1308+
mu > 100 ? 100 : mu, delay_feefactor);
13341309
if (!*flows || mu >= 100) {
13351310
ret = rq_log(
13361311
ctx, rq, LOG_UNUSUAL,
@@ -1411,3 +1386,27 @@ const char *default_routes(const tal_t *ctx, struct route_query *rq,
14111386
assert(ret != NULL);
14121387
return ret;
14131388
}
1389+
1390+
const char *default_routes(const tal_t *ctx, struct route_query *rq,
1391+
const struct gossmap_node *srcnode,
1392+
const struct gossmap_node *dstnode,
1393+
struct amount_msat amount, struct amount_msat maxfee,
1394+
u32 finalcltv, u32 maxdelay, struct flow ***flows,
1395+
double *probability)
1396+
{
1397+
return linear_routes(ctx, rq, srcnode, dstnode, amount, maxfee,
1398+
finalcltv, maxdelay, flows, probability, minflow);
1399+
}
1400+
1401+
const char *single_path_routes(const tal_t *ctx, struct route_query *rq,
1402+
const struct gossmap_node *srcnode,
1403+
const struct gossmap_node *dstnode,
1404+
struct amount_msat amount,
1405+
struct amount_msat maxfee, u32 finalcltv,
1406+
u32 maxdelay, struct flow ***flows,
1407+
double *probability)
1408+
{
1409+
return linear_routes(ctx, rq, srcnode, dstnode, amount, maxfee,
1410+
finalcltv, maxdelay, flows, probability,
1411+
single_path_flow);
1412+
}

plugins/askrene/mcf.h

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,7 @@ struct flow **minflow(const tal_t *ctx,
3131
const struct gossmap_node *target,
3232
struct amount_msat amount,
3333
u32 mu,
34-
double delay_feefactor,
35-
bool single_part);
34+
double delay_feefactor);
3635

3736
/**
3837
* API for min cost single path.
@@ -67,9 +66,18 @@ struct amount_msat linear_flow_cost(const struct flow *flow,
6766
const char *default_routes(const tal_t *ctx, struct route_query *rq,
6867
const struct gossmap_node *srcnode,
6968
const struct gossmap_node *dstnode,
70-
struct amount_msat amount, bool single_path,
69+
struct amount_msat amount,
7170
struct amount_msat maxfee, u32 finalcltv,
7271
u32 maxdelay, struct flow ***flows,
7372
double *probability);
7473

74+
/* A wrapper to the single-path constrained solver. */
75+
const char *single_path_routes(const tal_t *ctx, struct route_query *rq,
76+
const struct gossmap_node *srcnode,
77+
const struct gossmap_node *dstnode,
78+
struct amount_msat amount,
79+
struct amount_msat maxfee, u32 finalcltv,
80+
u32 maxdelay, struct flow ***flows,
81+
double *probability);
82+
7583
#endif /* LIGHTNING_PLUGINS_ASKRENE_MCF_H */

0 commit comments

Comments
 (0)