Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 19 additions & 2 deletions plugins/askrene/askrene.c
Original file line number Diff line number Diff line change
Expand Up @@ -399,6 +399,7 @@ struct getroutes_info {
struct node_id source, dest;
struct amount_msat amount, maxfee;
u32 finalcltv, maxdelay;
u64 needed_features;
/* algorithm selection, only dev */
enum algorithm dev_algo;
const char **layers;
Expand Down Expand Up @@ -630,6 +631,12 @@ static struct command_result *do_getroutes(struct command *cmd,
goto fail;
}

if (!node_has_needed_features(askrene->gossmap, srcnode, info->needed_features)) {
err = rq_log(tmpctx, rq, LOG_INFORM, "Source node %s does not have the needed features",
fmt_node_id(tmpctx, &info->source));
goto fail;
}

/* checkout the destination */
const struct gossmap_node *dstnode =
gossmap_find_node(askrene->gossmap, &info->dest);
Expand All @@ -640,6 +647,12 @@ static struct command_result *do_getroutes(struct command *cmd,
goto fail;
}

if (!node_has_needed_features(askrene->gossmap, dstnode, info->needed_features)) {
err = rq_log(tmpctx, rq, LOG_INFORM, "Destination node %s does not have the needed features",
fmt_node_id(tmpctx, &info->dest));
goto fail;
}

/* auto.no_mpp_support layer overrides any choice of algorithm. */
if (have_layer(info->layers, "auto.no_mpp_support") &&
info->dev_algo != ALGO_SINGLE_PATH) {
Expand All @@ -663,12 +676,12 @@ static struct command_result *do_getroutes(struct command *cmd,
if (info->dev_algo == ALGO_SINGLE_PATH) {
err = single_path_routes(rq, rq, deadline, srcnode, dstnode, info->amount,
info->maxfee, info->finalcltv,
info->maxdelay, &flows, &probability);
info->maxdelay, info->needed_features, &flows, &probability);
} else {
assert(info->dev_algo == ALGO_DEFAULT);
err = default_routes(rq, rq, deadline, srcnode, dstnode, info->amount,
info->maxfee, info->finalcltv,
info->maxdelay, &flows, &probability);
info->maxdelay, info->needed_features, &flows, &probability);
}
struct timerel time_delta = timemono_between(time_mono(), time_start);

Expand Down Expand Up @@ -821,6 +834,7 @@ static struct command_result *json_getroutes(struct command *cmd,
u32 *finalcltv, *maxdelay;
enum algorithm *dev_algo;
u32 *maxparts;
u64* needed_features;

if (!param_check(cmd, buffer, params,
p_req("source", param_node_id, &source),
Expand All @@ -835,6 +849,8 @@ static struct command_result *json_getroutes(struct command *cmd,
default_maxparts),
p_opt_dev("dev_algorithm", param_algorithm,
&dev_algo, ALGO_DEFAULT),
p_opt_def("needed_features", param_u64, &needed_features,
0),
NULL))
return command_param_failed();
plugin_log(cmd->plugin, LOG_TRACE, "%s called: %.*s", __func__,
Expand Down Expand Up @@ -870,6 +886,7 @@ static struct command_result *json_getroutes(struct command *cmd,
info->additional_costs = tal(info, struct additional_cost_htable);
additional_cost_htable_init(info->additional_costs);
info->maxparts = *maxparts;
info->needed_features = *needed_features;

if (have_layer(info->layers, "auto.localchans")) {
struct out_req *req;
Expand Down
54 changes: 42 additions & 12 deletions plugins/askrene/mcf.c
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,11 @@
#include <assert.h>
#include <ccan/asort/asort.h>
#include <ccan/bitmap/bitmap.h>
#include <ccan/bitops/bitops.h>
#include <ccan/list/list.h>
#include <ccan/tal/str/str.h>
#include <ccan/tal/tal.h>
#include <common/features.h>
#include <common/utils.h>
#include <float.h>
#include <inttypes.h>
Expand Down Expand Up @@ -301,6 +303,8 @@ struct pay_parameters {

double delay_feefactor;
double base_fee_penalty;

u64 needed_features;
};

/* Helper function.
Expand Down Expand Up @@ -575,6 +579,8 @@ static void init_linear_network(const tal_t *ctx,
{
const u32 node_id = gossmap_node_idx(gossmap,node);

if (!node_has_needed_features(gossmap, node, params->needed_features)) goto next;

for(size_t j=0;j<node->num_chans;++j)
{
int half;
Expand Down Expand Up @@ -642,6 +648,7 @@ static void init_linear_network(const tal_t *ctx,
(*arc_fee_cost)[dual.idx] = -fee_cost;
}
}
next:;
}
}

Expand Down Expand Up @@ -971,7 +978,7 @@ struct flow **minflow(const tal_t *ctx,
const struct gossmap_node *target,
struct amount_msat amount,
u32 mu,
double delay_feefactor)
double delay_feefactor, u64 needed_features)
{
struct flow **flow_paths;
/* We allocate everything off this, and free it at the end,
Expand Down Expand Up @@ -1006,6 +1013,7 @@ struct flow **minflow(const tal_t *ctx,

params->delay_feefactor = delay_feefactor;
params->base_fee_penalty = base_fee_penalty_estimate(amount);
params->needed_features = needed_features;

// build the uncertainty network with linearization and residual arcs
struct graph *graph;
Expand Down Expand Up @@ -1099,6 +1107,8 @@ static void init_linear_network_single_path(
node = gossmap_next_node(gossmap, node)) {
const u32 node_id = gossmap_node_idx(gossmap, node);

if (!node_has_needed_features(gossmap, node, params->needed_features)) goto next;

for (size_t j = 0; j < node->num_chans; ++j) {
int half;
const struct gossmap_chan *c =
Expand Down Expand Up @@ -1164,6 +1174,7 @@ static void init_linear_network_single_path(
fee_msat +
params->delay_feefactor * c->half[half].delay;
}
next:;
}
}

Expand All @@ -1172,7 +1183,7 @@ struct flow **single_path_flow(const tal_t *ctx, const struct route_query *rq,
const struct gossmap_node *source,
const struct gossmap_node *target,
struct amount_msat amount, u32 mu,
double delay_feefactor)
double delay_feefactor, u64 needed_features)
{
struct flow **flow_paths;
/* We allocate everything off this, and free it at the end,
Expand All @@ -1189,6 +1200,7 @@ struct flow **single_path_flow(const tal_t *ctx, const struct route_query *rq,
params->accuracy = amount;
params->delay_feefactor = delay_feefactor;
params->base_fee_penalty = base_fee_penalty_estimate(amount);
params->needed_features = needed_features;

struct graph *graph;
double *arc_prob_cost;
Expand Down Expand Up @@ -1350,11 +1362,12 @@ linear_routes(const tal_t *ctx, struct route_query *rq,
const struct gossmap_node *srcnode,
const struct gossmap_node *dstnode, struct amount_msat amount,
struct amount_msat maxfee, u32 finalcltv, u32 maxdelay,
struct flow ***flows, double *probability,
u64 needed_features, struct flow ***flows, double *probability,
struct flow **(*solver)(const tal_t *, const struct route_query *,
const struct gossmap_node *,
const struct gossmap_node *,
struct amount_msat, u32, double))
struct amount_msat, u32, double,
u64))
{
const tal_t *working_ctx = tal(ctx, tal_t);
const char *error_message;
Expand Down Expand Up @@ -1398,11 +1411,13 @@ linear_routes(const tal_t *ctx, struct route_query *rq,
SINGLE_PATH_THRESHOLD)) {
new_flows = single_path_flow(working_ctx, rq, srcnode,
dstnode, amount_to_deliver,
mu, delay_feefactor);
mu, delay_feefactor,
needed_features);
} else {
new_flows =
solver(working_ctx, rq, srcnode, dstnode,
amount_to_deliver, mu, delay_feefactor);
amount_to_deliver, mu, delay_feefactor,
needed_features);
}

if (!new_flows) {
Expand Down Expand Up @@ -1630,11 +1645,11 @@ const char *default_routes(const tal_t *ctx, struct route_query *rq,
const struct gossmap_node *srcnode,
const struct gossmap_node *dstnode,
struct amount_msat amount, struct amount_msat maxfee,
u32 finalcltv, u32 maxdelay, struct flow ***flows,
double *probability)
u32 finalcltv, u32 maxdelay, u64 needed_features,
struct flow ***flows, double *probability)
{
return linear_routes(ctx, rq, deadline, srcnode, dstnode, amount, maxfee,
finalcltv, maxdelay, flows, probability, minflow);
finalcltv, maxdelay, needed_features, flows, probability, minflow);
}

const char *single_path_routes(const tal_t *ctx, struct route_query *rq,
Expand All @@ -1643,10 +1658,25 @@ const char *single_path_routes(const tal_t *ctx, struct route_query *rq,
const struct gossmap_node *dstnode,
struct amount_msat amount,
struct amount_msat maxfee, u32 finalcltv,
u32 maxdelay, struct flow ***flows,
double *probability)
u32 maxdelay, u64 needed_features,
struct flow ***flows, double *probability)
{
return linear_routes(ctx, rq, deadline, srcnode, dstnode, amount, maxfee,
finalcltv, maxdelay, flows, probability,
finalcltv, maxdelay, needed_features, flows, probability,
single_path_flow);
}

bool node_has_needed_features(const struct gossmap *map,
const struct gossmap_node *n,
u64 needed_features)
{
/* It must have all the features we need */
while (needed_features) {
int feature = bitops_ls64(needed_features);
if (gossmap_node_get_feature(map, n, feature) == -1)
return false;
needed_features &= ~(1ULL << feature);
}
return true;
}

19 changes: 13 additions & 6 deletions plugins/askrene/mcf.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ struct route_query;
* @single_part: don't do MCF at all, just create a single flow.
*
* @delay_feefactor converts 1 block delay into msat, as if it were an additional
* @needed_features: needed features for the nodes to be considered
* fee. So if a CLTV delay on a node is 5 blocks, that's treated as if it
* were a fee of 5 * @delay_feefactor.
*
Expand All @@ -31,7 +32,7 @@ struct flow **minflow(const tal_t *ctx,
const struct gossmap_node *target,
struct amount_msat amount,
u32 mu,
double delay_feefactor);
double delay_feefactor, u64 needed_features);

/**
* API for min cost single path.
Expand All @@ -44,6 +45,7 @@ struct flow **minflow(const tal_t *ctx,
* @delay_feefactor: convert 1 block delay into msat.
*
* @delay_feefactor converts 1 block delay into msat, as if it were an additional
* @needed_features: needed features for the nodes to be considered
* fee. So if a CLTV delay on a node is 5 blocks, that's treated as if it
* were a fee of 5 * @delay_feefactor.
*
Expand All @@ -53,7 +55,7 @@ struct flow **single_path_flow(const tal_t *ctx, const struct route_query *rq,
const struct gossmap_node *source,
const struct gossmap_node *target,
struct amount_msat amount, u32 mu,
double delay_feefactor);
double delay_feefactor, u64 needed_features);

/* To sanity check: this is the approximation mcf uses for the cost
* of each channel. */
Expand All @@ -69,8 +71,8 @@ const char *default_routes(const tal_t *ctx, struct route_query *rq,
const struct gossmap_node *dstnode,
struct amount_msat amount,
struct amount_msat maxfee, u32 finalcltv,
u32 maxdelay, struct flow ***flows,
double *probability);
u32 maxdelay, u64 needed_features,
struct flow ***flows, double *probability);

/* A wrapper to the single-path constrained solver. */
const char *single_path_routes(const tal_t *ctx, struct route_query *rq,
Expand All @@ -79,7 +81,12 @@ const char *single_path_routes(const tal_t *ctx, struct route_query *rq,
const struct gossmap_node *dstnode,
struct amount_msat amount,
struct amount_msat maxfee, u32 finalcltv,
u32 maxdelay, struct flow ***flows,
double *probability);
u32 maxdelay, u64 needed_features,
struct flow ***flows, double *probability);

bool node_has_needed_features(const struct gossmap *map,
const struct gossmap_node *n,
u64 needed_features);


#endif /* LIGHTNING_PLUGINS_ASKRENE_MCF_H */
Loading