paymod: Fix the routehints being lost when retrying

We were removing the current hint from the list and not inheriting the current
routehint, so we'd be forgetting a hint at each retry. Now we keep the array
unchanged in the root, and simply skip the ones that are not usable given the
current information we have about the channels (in the form of channel_hints).

Fixes #3861
This commit is contained in:
Christian Decker
2020-07-21 22:09:54 +02:00
committed by Rusty Russell
parent d289ee64a1
commit e76bf541ad

View File

@@ -1765,14 +1765,12 @@ static bool routehint_excluded(struct payment *p,
static struct route_info *next_routehint(struct routehints_data *d, static struct route_info *next_routehint(struct routehints_data *d,
struct payment *p) struct payment *p)
{ {
while (tal_count(d->routehints) > 0) { /* FIXME: Add a pseudorandom offset to rotate between the routehints
if (!routehint_excluded(p, d->routehints[0])) { * we use, similar to what we'd do by randomizing the routes. */
d->current_routehint = d->routehints[0]; for (size_t i=0; i<tal_count(d->routehints); i++) {
tal_arr_remove(&d->routehints, 0); if (!routehint_excluded(p, d->routehints[i])) {
return d->current_routehint; return d->routehints[i];
} }
tal_free(d->routehints[0]);
tal_arr_remove(&d->routehints, 0);
} }
return NULL; return NULL;
} }
@@ -1821,17 +1819,19 @@ static void routehint_step_cb(struct routehints_data *d, struct payment *p)
if (root->invoice == NULL || root->invoice->routes == NULL) if (root->invoice == NULL || root->invoice->routes == NULL)
return payment_continue(p); return payment_continue(p);
/* The root payment gets the unmodified routehints, children may /* We filter out non-functional routehints once at the
* start dropping some as they learn that they were not * beginning, and every other payment will filter out the
* functional. */ * exluded ones on the fly. */
if (p->parent == NULL) { if (p->parent == NULL) {
d->routehints = filter_routehints(d, p->local_id, d->routehints = filter_routehints(d, p->local_id,
p->invoice->routes); p->invoice->routes);
} else { } else {
pd = payment_mod_get_data(p->parent, pd = payment_mod_get_data(p->parent,
&routehints_pay_mod); &routehints_pay_mod);
d->routehints = tal_dup_talarr(d, struct route_info *, /* Since we don't modify the list of routehints after
pd->routehints); * the root has filtered them we can just shared a
* pointer here. */
d->routehints = pd->routehints;
} }
d->current_routehint = next_routehint(d, p); d->current_routehint = next_routehint(d, p);
@@ -1847,6 +1847,11 @@ static void routehint_step_cb(struct routehints_data *d, struct payment *p)
p->getroute->cltv = p->getroute->cltv =
route_cltv(p->getroute->cltv, d->current_routehint, route_cltv(p->getroute->cltv, d->current_routehint,
tal_count(d->current_routehint)); tal_count(d->current_routehint));
plugin_log(p->plugin, LOG_DBG, "Using routehint %s (%s) cltv_delta=%d",
type_to_string(tmpctx, struct node_id, &d->current_routehint->pubkey),
type_to_string(tmpctx, struct short_channel_id, &d->current_routehint->short_channel_id),
d->current_routehint->cltv_expiry_delta
);
} }
} else if (p->step == PAYMENT_STEP_GOT_ROUTE) { } else if (p->step == PAYMENT_STEP_GOT_ROUTE) {
/* Now it's time to stitch the two partial routes together. */ /* Now it's time to stitch the two partial routes together. */
@@ -1886,8 +1891,8 @@ static void routehint_step_cb(struct routehints_data *d, struct payment *p)
static struct routehints_data *routehint_data_init(struct payment *p) static struct routehints_data *routehint_data_init(struct payment *p)
{ {
/* We defer the actual initialization to the step callback when we have /* We defer the actual initialization to the step callback when
* the invoice attached. */ * we have the invoice attached. */
return talz(p, struct routehints_data); return talz(p, struct routehints_data);
} }