paymod: Check if destination is reachable at all directly at startup

This does two things: it checks if the destination of the payment is at all
reachable without routehints, and if it is it adds a direct attempt as option
to the routehints in the form of a NULL routehint. It also simplifies the
selection of the routehint since the direct case is no longer special, instead
we just return a NULL routehint as if it were a normal routehint.
This commit is contained in:
Christian Decker 2020-07-23 10:52:08 +02:00
parent 497b18ba33
commit b78aa3fb25
2 changed files with 69 additions and 10 deletions

View File

@ -1770,19 +1770,14 @@ static bool routehint_excluded(struct payment *p,
static struct route_info *next_routehint(struct routehints_data *d,
struct payment *p)
{
/* Implements a random selection of a routehint, or none in 1/numhints
* cases, by starting the iteration of the routehints in a random
* order, and adding a virtual NULL result at the end. */
size_t numhints = tal_count(d->routehints);
size_t offset = pseudorand(numhints + 1);
size_t offset = pseudorand(numhints);
struct route_info *curr;
for (size_t i=0; i<tal_count(d->routehints); i++) {
size_t curr = (offset + i) % (numhints + 1);
if (curr == numhints)
return NULL;
if (!routehint_excluded(p, d->routehints[curr]))
return d->routehints[i];
curr = d->routehints[(offset + i) % numhints];
if (curr == NULL || !routehint_excluded(p, curr))
return curr;
}
return NULL;
}
@ -1821,6 +1816,58 @@ static u32 route_cltv(u32 cltv,
return cltv;
}
static struct command_result *routehint_getroute_result(struct command *cmd,
const char *buffer,
const jsmntok_t *toks,
struct payment *p)
{
struct payment *root = payment_root(p);
const jsmntok_t *rtok = json_get_member(buffer, toks, "route");
struct routehints_data *d = payment_mod_routehints_get_data(root);
/* If there was a route the destination is reachable without
* routehints. */
d->destination_reachable = (rtok != NULL);
if (d->destination_reachable)
tal_arr_expand(&d->routehints, NULL);
d->current_routehint = next_routehint(d, p);
plugin_log(p->plugin, LOG_DBG,
"The destination is%s directly reachable %s attempts "
"without routehints",
d->destination_reachable ? "" : " not",
d->destination_reachable ? "including" : "excluding");
/* Now we can continue on our merry way. */
payment_continue(p);
/* Let payment_finished_ handle this, so we mark it as pending */
return command_still_pending(cmd);
}
static void routehint_check_reachable(struct payment *p)
{
struct out_req *req;
/* Start a tiny exploratory getroute request, so we
* know whether we stand any chance of reaching the
* destination without routehints. This will later be
* used to mix in attempts without routehints. */
req = jsonrpc_request_start(p->plugin, NULL, "getroute",
routehint_getroute_result,
routehint_getroute_result, p);
json_add_node_id(req->js, "id", p->destination);
json_add_amount_msat_only(req->js, "msatoshi", AMOUNT_MSAT(1000));
json_add_num(req->js, "maxhops", 20);
json_add_num(req->js, "riskfactor", 10);
send_outreq(p->plugin, req);
plugin_log(p->plugin, LOG_DBG,
"Asking gossipd whether %s is reachable "
"without routehints.",
type_to_string(tmpctx, struct node_id, p->destination));
}
static void routehint_step_cb(struct routehints_data *d, struct payment *p)
{
struct routehints_data *pd;
@ -1837,6 +1884,14 @@ static void routehint_step_cb(struct routehints_data *d, struct payment *p)
if (p->parent == NULL) {
d->routehints = filter_routehints(d, p->local_id,
p->invoice->routes);
plugin_log(p->plugin, LOG_DBG,
"After filtering routehints we're left with "
"%zu usable hints",
tal_count(d->routehints));
/* Do not continue normally, instead go and check if
* we can reach the destination directly. */
return routehint_check_reachable(p);
} else {
pd = payment_mod_get_data(p->parent,
&routehints_pay_mod);
@ -1844,6 +1899,7 @@ static void routehint_step_cb(struct routehints_data *d, struct payment *p)
* the root has filtered them we can just shared a
* pointer here. */
d->routehints = pd->routehints;
d->destination_reachable = pd->destination_reachable;
}
d->current_routehint = next_routehint(d, p);

View File

@ -299,6 +299,9 @@ struct routehints_data {
/* We modify the CLTV in the getroute call, so we need to remember
* what the final cltv delta was so we re-apply it correctly. */
u32 final_cltv;
/* Is the destination reachable without any routehints? */
bool destination_reachable;
};
struct exemptfee_data {