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
63 changes: 61 additions & 2 deletions plugins/askrene/askrene.c
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@
#include <plugins/askrene/child/child_log.h>
#include <plugins/askrene/layer.h>
#include <plugins/askrene/reserve.h>
#include <stdlib.h>
#include <string.h>
#include <sys/wait.h>
#include <wire/wire_io.h>
#include <wire/wire_sync.h>
Expand Down Expand Up @@ -91,6 +93,44 @@ static struct command_result *param_direction(struct command *cmd,
return NULL;
}

static bool is_maxhops(const char *s)
{
return strncmp(s, "maxhops=", strlen("maxhops=")) == 0;
}

static bool parse_maxhops(const char *s, u32 *v)
{
if(!is_maxhops(s))
return false;

const char *num = s + strlen("maxhops=");
char *end;
unsigned long n;

if (*num < '0' || *num > '9')
return false;
errno = 0;
n = strtoul(num, &end, 10);
if (*end != '\0' || errno == ERANGE || n > UINT32_MAX)
return false;
*v = n;
return true;
}

static u32 extract_maxhops(const char ***layers, u32 default_maxhops)
{
u32 maxhops = default_maxhops;
for (size_t i = 0; i < tal_count(*layers); i++) {
u32 v;
if (parse_maxhops((*layers)[i], &v)) {
maxhops = v;
tal_arr_remove(layers, i);
i--;
}
}
return maxhops;
}
Comment on lines +120 to +132

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

extract_maxhops keeps the last maxhops= entry. xpay adds its own maxhops=<budget> first and appends the user's layers (the xpay layers parameter and xpay-layers) after it, so a user layer such as "maxhops=50" replaces the onion budget. askrene then returns a route longer than the budget, and getroutes_done logs BROKEN and gives up. Keeping the minimum of all maxhops= entries would keep xpay's limit authoritative.


/* Valid, known layers */
static struct command_result *param_layer_names(struct command *cmd,
const char *name,
Expand All @@ -112,6 +152,15 @@ static struct command_result *param_layer_names(struct command *cmd,
"should be a string");
(*arr)[i] = json_strdup(*arr, buffer, t);

if (is_maxhops((*arr)[i])) {
u32 v;
if (!parse_maxhops((*arr)[i], &v))
return command_fail_badparam(
cmd, name, buffer, t,
"maxhops must be a u32");
continue;
}

/* Must be a known layer name */
if (streq((*arr)[i], "auto.localchans")
|| streq((*arr)[i], "auto.sourcefree")
Expand Down Expand Up @@ -359,6 +408,7 @@ struct getroutes_info {
/* Non-NULL if we are told to use "auto.localchans" */
struct layer *local_layer;
u32 maxparts;
u32 maxhops;
};

static void add_layer(const struct layer ***layers,
Expand Down Expand Up @@ -716,7 +766,11 @@ static struct command_result *do_getroutes(struct command *cmd,
take(capacities),
info->dev_algo == ALGO_SINGLE_PATH,
deadline, srcnode, dstnode, info->amount,
info->maxfee, info->finalcltv, info->maxdelay, info->maxparts,
info->maxfee,
info->finalcltv,
info->maxdelay,
info->maxparts,
info->maxhops,
include_fees,
cmd->id, cmd->filter,
include_next_node_id,
Expand Down Expand Up @@ -900,7 +954,7 @@ static struct command_result *json_getroutes(struct command *cmd,
/* FIXME: Typo in spec for CLTV in descripton! But it breaks our spelling check, so we omit it above */
const u32 maxdelay_allowed = 2016;
struct askrene *askrene = get_askrene(cmd->plugin);
const u32 default_maxparts = 100;
const u32 default_maxparts = 100, default_maxhops = 100;
struct getroutes_info *info = tal(cmd, struct getroutes_info);
/* param functions require pointers */
struct node_id *source, *dest;
Expand Down Expand Up @@ -962,6 +1016,11 @@ static struct command_result *json_getroutes(struct command *cmd,
info->additional_costs = new_htable(info, additional_cost_htable);
info->maxparts = *maxparts;

/* A trick to pass maxhops without introducing a new RPC or requiring
* developer option. We pass maxhops as a layer string, eg.
* "maxhops=10" */
info->maxhops = extract_maxhops(&info->layers, default_maxhops);

if (askrene->num_live_requests >= askrene->max_children) {
cmd_log(tmpctx, cmd, LOG_INFORM,
"Too many running at once (%zu vs %u): waiting",
Expand Down
11 changes: 7 additions & 4 deletions plugins/askrene/child/child.c
Original file line number Diff line number Diff line change
Expand Up @@ -219,8 +219,11 @@ void run_child(const struct gossmap *gossmap,
const struct gossmap_node *srcnode,
const struct gossmap_node *dstnode,
struct amount_msat amount, struct amount_msat maxfee,
u32 finalcltv, u32 maxdelay, size_t maxparts,
bool include_fees,
u32 finalcltv,
u32 maxdelay,
size_t maxparts,
u32 maxhops,
bool include_fees,
const char *cmd_id,
struct json_filter *cmd_filter,
bool include_next_node_id,
Expand All @@ -243,11 +246,11 @@ void run_child(const struct gossmap *gossmap,
if (single_path) {
err = single_path_routes(rq, rq, deadline, srcnode, dstnode,
amount, maxfee, finalcltv,
maxdelay, &flows, &probability, &ecode);
maxdelay, maxhops, &flows, &probability, &ecode);
} else {
err = default_routes(rq, rq, deadline, srcnode, dstnode,
amount, maxfee, finalcltv, maxdelay,
maxparts, &flows, &probability, &ecode);
maxparts, maxhops, &flows, &probability, &ecode);
}
if (err) {
write_all(replyfd, &ecode, sizeof(ecode));
Expand Down
5 changes: 4 additions & 1 deletion plugins/askrene/child/child.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,10 @@ void run_child(const struct gossmap *gossmap,
const struct gossmap_node *srcnode,
const struct gossmap_node *dstnode,
struct amount_msat amount, struct amount_msat maxfee,
u32 finalcltv, u32 maxdelay, size_t maxparts,
u32 finalcltv,
u32 maxdelay,
size_t maxparts,
u32 maxhops,
bool include_fees,
const char *cmd_id,
struct json_filter *cmd_filter,
Expand Down
11 changes: 11 additions & 0 deletions plugins/askrene/child/flow.c
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,17 @@ u64 flows_worst_delay(struct flow **flows)
return maxdelay;
}

u32 flows_worst_length(struct flow **flows)
{
u32 maxlen = 0;
for (size_t i = 0; i < tal_count(flows); i++) {
u32 len = tal_count(flows[i]->path);
if (len > maxlen)
maxlen = len;
}
return maxlen;
}

const char *fmt_flows_step_scid(const tal_t *ctx,
const struct route_query *rq,
const struct flow *flow, size_t i)
Expand Down
3 changes: 3 additions & 0 deletions plugins/askrene/child/flow.h
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,9 @@ u64 flow_delay(const struct flow *flow);
/* Max CLTV any of these flows requires */
u64 flows_worst_delay(struct flow **flows);

/* Max number of hops any of these flows requires */
u32 flows_worst_length(struct flow **flows);

const char *fmt_flows_step_scid(const tal_t *ctx,
const struct route_query *rq,
const struct flow *flow, size_t i);
Expand Down
Loading
Loading