mirror of
https://github.com/aljazceru/lightning.git
synced 2025-12-19 23:24:27 +01:00
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.
This commit is contained in:
committed by
Rusty Russell
parent
3aad86ff9d
commit
094eac4e95
@@ -489,14 +489,9 @@ static void payment_getroute_add_excludes(struct payment *p,
|
|||||||
json_add_node_id(js, NULL, &nodes[i]);
|
json_add_node_id(js, NULL, &nodes[i]);
|
||||||
|
|
||||||
/* And make sure we don't route in a circle via the routehint! */
|
/* And make sure we don't route in a circle via the routehint! */
|
||||||
if (p->temp_exclusion) {
|
if (p->temp_exclusion)
|
||||||
struct short_channel_id_dir scidd;
|
for (size_t i = 0; i < tal_count(p->temp_exclusion); ++i)
|
||||||
scidd.scid = *p->temp_exclusion;
|
json_add_string(js, NULL, p->temp_exclusion[i]);
|
||||||
for (size_t dir = 0; dir < 2; dir++) {
|
|
||||||
scidd.dir = dir;
|
|
||||||
json_add_short_channel_id_dir(js, NULL, &scidd);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
json_array_end(js);
|
json_array_end(js);
|
||||||
}
|
}
|
||||||
@@ -1841,6 +1836,47 @@ static u32 route_cltv(u32 cltv,
|
|||||||
return 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
|
/* Change the destination and compute the final msatoshi amount to send to the
|
||||||
* routehint entry point. */
|
* routehint entry point. */
|
||||||
static void routehint_pre_getroute(struct routehints_data *d, struct payment *p)
|
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);
|
have_more = (d->offset < tal_count(d->routehints) - 1);
|
||||||
p->failroute_retry = have_more;
|
p->failroute_retry = have_more;
|
||||||
|
|
||||||
|
p->temp_exclusion = tal_free(p->temp_exclusion);
|
||||||
|
|
||||||
if (d->current_routehint != NULL) {
|
if (d->current_routehint != NULL) {
|
||||||
if (!route_msatoshi(&p->getroute->amount, p->amount,
|
if (!route_msatoshi(&p->getroute->amount, p->amount,
|
||||||
d->current_routehint,
|
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
|
/* Exclude the entrypoint to the routehint, so we don't end up
|
||||||
* going through the destination to the entrypoint. */
|
* going through the destination to the entrypoint. */
|
||||||
p->temp_exclusion = &d->current_routehint[0].short_channel_id;
|
p->temp_exclusion = routehint_generate_exclusion_list(p, d->current_routehint, p);
|
||||||
} else {
|
} else
|
||||||
plugin_log(p->plugin, LOG_DBG, "Not using a routehint");
|
plugin_log(p->plugin, LOG_DBG, "Not using a routehint");
|
||||||
p->temp_exclusion = NULL;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct command_result *routehint_getroute_result(struct command *cmd,
|
static struct command_result *routehint_getroute_result(struct command *cmd,
|
||||||
|
|||||||
@@ -232,8 +232,8 @@ struct payment {
|
|||||||
struct channel_hint *channel_hints;
|
struct channel_hint *channel_hints;
|
||||||
struct node_id *excluded_nodes;
|
struct node_id *excluded_nodes;
|
||||||
|
|
||||||
/* Optional temporarily excluded channel (i.e. this routehint) */
|
/* Optional temporarily excluded channels/nodes (i.e. this routehint) */
|
||||||
struct short_channel_id *temp_exclusion;
|
const char **temp_exclusion;
|
||||||
|
|
||||||
struct payment_result *result;
|
struct payment_result *result;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user