Browse Source

plugins/libplugin-pay.c: Properly handle exclusions for routehints with two hops or more.

Arguably a low-priority bug since no current node ever generates routehints longer
than one hop.

However, it is possible as an edge case, if the destination is directly accessible
*and* supports multiple channels, that we route through the destination, one of the
*other* channels it has not in the routehint, to the entry point, and then through
the routehint.

This change removes the risk of the above edge case.

Changelog-None: arguably a low-priority bug.
bump-pyln-proto
ZmnSCPxj jxPCSnmZ 4 years ago
committed by Rusty Russell
parent
commit
094eac4e95
  1. 60
      plugins/libplugin-pay.c
  2. 4
      plugins/libplugin-pay.h

60
plugins/libplugin-pay.c

@ -489,14 +489,9 @@ static void payment_getroute_add_excludes(struct payment *p,
json_add_node_id(js, NULL, &nodes[i]);
/* And make sure we don't route in a circle via the routehint! */
if (p->temp_exclusion) {
struct short_channel_id_dir scidd;
scidd.scid = *p->temp_exclusion;
for (size_t dir = 0; dir < 2; dir++) {
scidd.dir = dir;
json_add_short_channel_id_dir(js, NULL, &scidd);
}
}
if (p->temp_exclusion)
for (size_t i = 0; i < tal_count(p->temp_exclusion); ++i)
json_add_string(js, NULL, p->temp_exclusion[i]);
json_array_end(js);
}
@ -1841,6 +1836,47 @@ static u32 route_cltv(u32 cltv,
return cltv;
}
/** routehint_generate_exclusion_list
*
* @brief generate a list of items to append to `excludes`
* parameter of `getroute`.
*
* @param ctx - the context to allocate off of.
* @param routehint - the actual routehint, a `tal` array.
* @param payment - the payment that we will create an
* exclusion list for.
*
* @return an array of strings that will be appended to the
* `excludes` parameter of `getroute`.
*/
static
const char **routehint_generate_exclusion_list(const tal_t *ctx,
struct route_info *routehint,
struct payment *payment)
{
const char **exc;
size_t i;
if (!routehint || tal_count(routehint) == 0)
/* Nothing to exclude. */
return NULL;
exc = tal_arr(ctx, const char *, 0);
/* Exclude every node except the first, because the first is
* the entry point to the routehint. */
for (i = 1 /* Skip the first! */; i < tal_count(routehint); ++i)
tal_arr_expand(&exc,
type_to_string(exc, struct node_id,
&routehint[i].pubkey));
/* Also exclude the destination, because it would be foolish to
* pass through it and *then* go to the routehint entry point. */
tal_arr_expand(&exc,
type_to_string(exc, struct node_id,
payment->destination));
return exc;
}
/* Change the destination and compute the final msatoshi amount to send to the
* routehint entry point. */
static void routehint_pre_getroute(struct routehints_data *d, struct payment *p)
@ -1853,6 +1889,8 @@ static void routehint_pre_getroute(struct routehints_data *d, struct payment *p)
have_more = (d->offset < tal_count(d->routehints) - 1);
p->failroute_retry = have_more;
p->temp_exclusion = tal_free(p->temp_exclusion);
if (d->current_routehint != NULL) {
if (!route_msatoshi(&p->getroute->amount, p->amount,
d->current_routehint,
@ -1873,11 +1911,9 @@ static void routehint_pre_getroute(struct routehints_data *d, struct payment *p)
/* Exclude the entrypoint to the routehint, so we don't end up
* going through the destination to the entrypoint. */
p->temp_exclusion = &d->current_routehint[0].short_channel_id;
} else {
p->temp_exclusion = routehint_generate_exclusion_list(p, d->current_routehint, p);
} else
plugin_log(p->plugin, LOG_DBG, "Not using a routehint");
p->temp_exclusion = NULL;
}
}
static struct command_result *routehint_getroute_result(struct command *cmd,

4
plugins/libplugin-pay.h

@ -232,8 +232,8 @@ struct payment {
struct channel_hint *channel_hints;
struct node_id *excluded_nodes;
/* Optional temporarily excluded channel (i.e. this routehint) */
struct short_channel_id *temp_exclusion;
/* Optional temporarily excluded channels/nodes (i.e. this routehint) */
const char **temp_exclusion;
struct payment_result *result;

Loading…
Cancel
Save