renepay: remove payment from route

Routes contain only routing information and the payment they're linked
to can be obtained through the payment_hash. We remove the dependency of
route building routines from the payment itself. In order to make
plain payment information available we define a payment_info structure.
This commit is contained in:
Lagrang3 2024-05-04 10:48:13 +01:00 committed by Rusty Russell
parent ca2b4e54ae
commit da00cae30b
14 changed files with 363 additions and 321 deletions

View file

@ -22,6 +22,7 @@ PLUGIN_RENEPAY_HDRS := \
plugins/renepay/dijkstra.h \
plugins/renepay/disabledmap.h \
plugins/renepay/payment.h \
plugins/renepay/payment_info.h \
plugins/renepay/chan_extra.h \
plugins/renepay/route.h \
plugins/renepay/routebuilder.h \

View file

@ -173,20 +173,21 @@ void json_add_payment(struct json_stream *s, const struct payment *payment)
{
assert(s);
assert(payment);
const struct payment_info *pinfo = &payment->payment_info;
if (payment->label != NULL)
json_add_string(s, "label", payment->label);
if (payment->invstr != NULL)
json_add_invstring(s, payment->invstr);
if (pinfo->label != NULL)
json_add_string(s, "label", pinfo->label);
if (pinfo->invstr != NULL)
json_add_invstring(s, pinfo->invstr);
json_add_amount_msat(s, "amount_msat", payment->amount);
json_add_sha256(s, "payment_hash", &payment->payment_hash);
json_add_node_id(s, "destination", &payment->destination);
json_add_amount_msat(s, "amount_msat", pinfo->amount);
json_add_sha256(s, "payment_hash", &pinfo->payment_hash);
json_add_node_id(s, "destination", &pinfo->destination);
if (payment->description)
json_add_string(s, "description", payment->description);
if (pinfo->description)
json_add_string(s, "description", pinfo->description);
json_add_timeabs(s, "created_at", payment->start_time);
json_add_timeabs(s, "created_at", pinfo->start_time);
json_add_u64(s, "groupid", payment->groupid);
json_add_u64(s, "parts", payment->next_partid);
@ -219,13 +220,14 @@ void json_add_payment(struct json_stream *s, const struct payment *payment)
// - number of parts?
}
void json_add_route(struct json_stream *js, const struct route *route)
void json_add_route(struct json_stream *js, const struct route *route,
const struct payment *payment)
{
assert(js);
assert(route);
struct payment *payment = route->payment;
assert(payment);
const struct payment_info *pinfo = &payment->payment_info;
assert(route->hops);
const size_t pathlen = tal_count(route->hops);
@ -245,10 +247,10 @@ void json_add_route(struct json_stream *js, const struct route *route)
json_object_end(js);
}
json_array_end(js);
json_add_sha256(js, "payment_hash", &payment->payment_hash);
json_add_sha256(js, "payment_hash", &pinfo->payment_hash);
if (payment->payment_secret)
json_add_secret(js, "payment_secret", payment->payment_secret);
if (pinfo->payment_secret)
json_add_secret(js, "payment_secret", pinfo->payment_secret);
/* FIXME: sendpay has a check that we don't total more than
* the exact amount, if we're setting partid (i.e. MPP).
@ -259,24 +261,24 @@ void json_add_route(struct json_stream *js, const struct route *route)
* The spec was loosened so you are actually allowed
* to overpay, so this check is now overzealous. */
if (pathlen > 0 &&
amount_msat_greater(route_delivers(route), payment->amount)) {
amount_msat_greater(route_delivers(route), pinfo->amount)) {
json_add_amount_msat(js, "amount_msat", route_delivers(route));
} else {
json_add_amount_msat(js, "amount_msat", payment->amount);
json_add_amount_msat(js, "amount_msat", pinfo->amount);
}
json_add_u64(js, "partid", route->key.partid);
json_add_u64(js, "groupid", route->key.groupid);
/* FIXME: some of these fields might not be required for all
* payment parts. */
json_add_string(js, "bolt11", payment->invstr);
json_add_string(js, "bolt11", pinfo->invstr);
if (payment->payment_metadata)
if (pinfo->payment_metadata)
json_add_hex_talarr(js, "payment_metadata",
payment->payment_metadata);
if (payment->label)
json_add_string(js, "label", payment->label);
if (payment->description)
json_add_string(js, "description", payment->description);
pinfo->payment_metadata);
if (pinfo->label)
json_add_string(js, "label", pinfo->label);
if (pinfo->description)
json_add_string(js, "description", pinfo->description);
}

View file

@ -14,6 +14,7 @@ struct payment_result *tal_sendpay_result_from_json(const tal_t *ctx,
void json_add_payment(struct json_stream *s, const struct payment *payment);
void json_add_route(struct json_stream *s, const struct route *route);
void json_add_route(struct json_stream *s, const struct route *route,
const struct payment *payment);
#endif /* LIGHTNING_PLUGINS_RENEPAY_JSON_H */

View file

@ -222,9 +222,10 @@ static struct command_result *previous_sendpays_done(struct command *cmd,
* succeed the payment, and when they fail we need to
* substract from the total. */
struct route *r = new_route(
pending_routes, payment, groupid, partid,
payment->payment_hash, this_msat, this_sent);
struct route *r =
new_route(pending_routes, groupid, partid,
payment->payment_info.payment_hash,
this_msat, this_sent);
assert(r);
tal_arr_expand(&pending_routes, r);
} else
@ -234,8 +235,8 @@ static struct command_result *previous_sendpays_done(struct command *cmd,
if (complete_groupid != INVALID_ID) {
/* There are completed sendpays, we don't need to do anything
* but summarize the result. */
payment->start_time.ts.tv_sec = complete_created_at;
payment->start_time.ts.tv_nsec = 0;
payment->payment_info.start_time.ts.tv_sec = complete_created_at;
payment->payment_info.start_time.ts.tv_nsec = 0;
payment->total_delivering = complete_msat;
payment->total_sent = complete_sent;
payment->next_partid = complete_parts + 1;
@ -261,7 +262,7 @@ static struct command_result *previous_sendpays_done(struct command *cmd,
max_pending_partid);
if (amount_msat_greater_eq(payment->total_delivering,
payment->amount)) {
payment->payment_info.amount)) {
/* Pending payment already pays the full amount, we
* better stop. */
return payment_fail(
@ -271,7 +272,8 @@ static struct command_result *previous_sendpays_done(struct command *cmd,
}
for (size_t j = 0; j < tal_count(pending_routes); j++) {
route_pending_register(pending_routes[j]);
route_pending_register(payment->routetracker,
pending_routes[j]);
}
} else {
@ -295,7 +297,8 @@ static struct command_result *previous_sendpays_cb(struct payment *payment)
cmd->plugin, cmd, "listsendpays", previous_sendpays_done,
payment_rpc_failure, payment);
json_add_sha256(req->js, "payment_hash", &payment->payment_hash);
json_add_sha256(req->js, "payment_hash",
&payment->payment_info.payment_hash);
return send_outreq(cmd->plugin, req);
}
@ -330,8 +333,10 @@ static struct command_result *selfpay_success(struct command *cmd,
const jsmntok_t *tok,
struct route *route)
{
struct payment *payment = route->payment;
struct payment *payment =
payment_map_get(pay_plugin->payment_map, route->key.payment_hash);
assert(payment);
struct preimage preimage;
const char *err;
err = json_scan(tmpctx, buf, tok, "{payment_preimage:%}",
@ -350,7 +355,8 @@ static struct command_result *selfpay_failure(struct command *cmd,
const jsmntok_t *tok,
struct route *route)
{
struct payment *payment = route->payment;
struct payment *payment =
payment_map_get(pay_plugin->payment_map, route->key.payment_hash);
assert(payment);
struct payment_result *result = tal_sendpay_result_from_json(tmpctx, buf, tok);
if (result == NULL)
@ -363,7 +369,8 @@ static struct command_result *selfpay_failure(struct command *cmd,
static struct command_result *selfpay_cb(struct payment *payment)
{
if (!node_id_eq(&pay_plugin->my_id, &payment->destination)) {
if (!node_id_eq(&pay_plugin->my_id,
&payment->payment_info.destination)) {
return payment_continue(payment);
}
@ -372,14 +379,16 @@ static struct command_result *selfpay_cb(struct payment *payment)
plugin_err(pay_plugin->plugin,
"Selfpay: cannot get a valid cmd.");
struct route *route = new_route(payment, payment, payment->groupid,
/*partid=*/0, payment->payment_hash,
payment->amount, payment->amount);
struct payment_info *pinfo = &payment->payment_info;
struct route *route =
new_route(payment, payment->groupid,
/*partid=*/0, pinfo->payment_hash,
pinfo->amount, pinfo->amount);
struct out_req *req;
req = jsonrpc_request_start(cmd->plugin, cmd, "sendpay",
selfpay_success, selfpay_failure, route);
route->hops = tal_arr(route, struct route_hop, 0);
json_add_route(req->js, route);
json_add_route(req->js, route, payment);
return send_outreq(cmd->plugin, req);
}
@ -640,13 +649,16 @@ static struct command_result *routehints_done(struct command *cmd UNUSED,
// FIXME are there route hints for B12?
assert(payment);
assert(payment->local_gossmods);
assert(payment->routehints);
const size_t nhints = tal_count(payment->routehints);
const struct node_id *destination = &payment->payment_info.destination;
const struct route_info **routehints = payment->payment_info.routehints;
assert(routehints);
const size_t nhints = tal_count(routehints);
/* Hints are added to the local_gossmods. */
for (size_t i = 0; i < nhints; i++) {
/* Each one, presumably, leads to the destination */
const struct route_info *r = payment->routehints[i];
const struct node_id *end = &payment->destination;
const struct route_info *r = routehints[i];
const struct node_id *end = destination;
for (int j = tal_count(r) - 1; j >= 0; j--) {
add_hintchan(payment, &r[j].pubkey, end,
@ -697,7 +709,8 @@ compute_routes_done(struct command *cmd UNUSED, const char *buf UNUSED,
struct amount_msat feebudget, fees_spent, remaining;
/* Total feebudget */
if (!amount_msat_sub(&feebudget, payment->maxspend, payment->amount))
if (!amount_msat_sub(&feebudget, payment->payment_info.maxspend,
payment->payment_info.amount))
plugin_err(pay_plugin->plugin, "%s: fee budget is negative?",
__PRETTY_FUNCTION__);
@ -713,7 +726,7 @@ compute_routes_done(struct command *cmd UNUSED, const char *buf UNUSED,
feebudget = AMOUNT_MSAT(0);
/* How much are we still trying to send? */
if (!amount_msat_sub(&remaining, payment->amount,
if (!amount_msat_sub(&remaining, payment->payment_info.amount,
payment->total_delivering))
plugin_err(pay_plugin->plugin,
"%s: total_delivering is greater than amount?",
@ -742,15 +755,18 @@ compute_routes_done(struct command *cmd UNUSED, const char *buf UNUSED,
payment->routes_computed = get_routes(
payment,
payment,
&payment->payment_info,
&pay_plugin->my_id,
&payment->destination,
&payment->payment_info.destination,
pay_plugin->gossmap,
pay_plugin->uncertainty,
payment->disabledmap,
remaining,
payment->final_cltv,
feebudget,
&payment->next_partid,
payment->groupid,
&errcode,
&err_msg);
@ -793,7 +809,7 @@ static struct command_result *send_routes_done(struct command *cmd,
for (size_t i = 0; i < tal_count(payment->routes_computed); i++) {
struct route *route = payment->routes_computed[i];
route_sendpay_request(cmd, route);
route_sendpay_request(cmd, route, payment);
payment_note(payment, LOG_INFORM,
"Sent route request: partid=%" PRIu64
@ -880,7 +896,7 @@ collect_results_done(struct command *cmd UNUSED, const char *buf UNUSED,
/* If we have the preimate that means one succeed, we
* inmediately finish the payment. */
if (!amount_msat_greater_eq(payment->total_delivering,
payment->amount)) {
payment->payment_info.amount)) {
plugin_err(
pay_plugin->plugin,
"%s: received a success sendpay for this "
@ -888,7 +904,8 @@ collect_results_done(struct command *cmd UNUSED, const char *buf UNUSED,
"is less than the payment amount %s.",
__PRETTY_FUNCTION__,
fmt_amount_msat(tmpctx, payment->total_delivering),
fmt_amount_msat(tmpctx, payment->amount));
fmt_amount_msat(tmpctx,
payment->payment_info.amount));
}
return payment_success(payment, take(payment_preimage));
}
@ -899,7 +916,7 @@ collect_results_done(struct command *cmd UNUSED, const char *buf UNUSED,
}
if (amount_msat_greater_eq(payment->total_delivering,
payment->amount)) {
payment->payment_info.amount)) {
/* There are no succeeds but we are still pending delivering the
* entire payment. We still need to collect more results. */
payment->have_results = false;
@ -973,7 +990,7 @@ static struct command_result *checktimeout_done(struct command *cmd UNUSED,
const jsmntok_t *result UNUSED,
struct payment *payment)
{
if (time_after(time_now(), payment->stop_time)) {
if (time_after(time_now(), payment->payment_info.stop_time)) {
return payment_fail(payment, PAY_STOPPED_RETRYING, "Timed out");
}
return payment_continue(payment);

View file

@ -35,51 +35,52 @@ struct payment *payment_new(
bool use_shadow)
{
struct payment *p = tal(ctx, struct payment);
struct payment_info *pinfo = &p->payment_info;
/* === Unique properties === */
assert(payment_hash);
p->payment_hash = *payment_hash;
pinfo->payment_hash = *payment_hash;
assert(invstr);
p->invstr = tal_strdup(p, invstr);
pinfo->invstr = tal_strdup(p, invstr);
p->label = tal_strdup_or_null(p, label);
p->description = tal_strdup_or_null(p, description);
p->payment_secret = tal_dup_or_null(p, struct secret, payment_secret);
p->payment_metadata = tal_dup_talarr(p, u8, payment_metadata);
pinfo->label = tal_strdup_or_null(p, label);
pinfo->description = tal_strdup_or_null(p, description);
pinfo->payment_secret = tal_dup_or_null(p, struct secret, payment_secret);
pinfo->payment_metadata = tal_dup_talarr(p, u8, payment_metadata);
if (taken(routehints))
p->routehints = tal_steal(p, routehints);
pinfo->routehints = tal_steal(p, routehints);
else {
/* Deep copy */
p->routehints =
pinfo->routehints =
tal_dup_talarr(p, const struct route_info *, routehints);
for (size_t i = 0; i < tal_count(p->routehints); i++)
p->routehints[i] =
tal_steal(p->routehints, p->routehints[i]);
for (size_t i = 0; i < tal_count(pinfo->routehints); i++)
pinfo->routehints[i] =
tal_steal(pinfo->routehints, pinfo->routehints[i]);
}
assert(destination);
p->destination = *destination;
p->amount = amount;
pinfo->destination = *destination;
pinfo->amount = amount;
/* === Payment attempt parameters === */
if (!amount_msat_add(&p->maxspend, amount, maxfee))
p->maxspend = AMOUNT_MSAT(UINT64_MAX);
p->maxdelay = maxdelay;
if (!amount_msat_add(&pinfo->maxspend, amount, maxfee))
pinfo->maxspend = AMOUNT_MSAT(UINT64_MAX);
pinfo->maxdelay = maxdelay;
p->start_time = time_now();
p->stop_time = timeabs_add(p->start_time, time_from_sec(retryfor));
pinfo->start_time = time_now();
pinfo->stop_time = timeabs_add(pinfo->start_time, time_from_sec(retryfor));
p->final_cltv = final_cltv;
pinfo->final_cltv = final_cltv;
/* === Developer options === */
p->base_fee_penalty = base_fee_penalty_millionths / 1e6;
p->prob_cost_factor = prob_cost_factor_millionths / 1e6;
p->delay_feefactor = riskfactor_millionths / 1e6;
p->min_prob_success = min_prob_success_millionths / 1e6;
p->use_shadow = use_shadow;
pinfo->base_fee_penalty = base_fee_penalty_millionths / 1e6;
pinfo->prob_cost_factor = prob_cost_factor_millionths / 1e6;
pinfo->delay_feefactor = riskfactor_millionths / 1e6;
pinfo->min_prob_success = min_prob_success_millionths / 1e6;
pinfo->use_shadow = use_shadow;
/* === Public State === */
@ -105,7 +106,7 @@ struct payment *payment_new(
p->waitresult_timer = NULL;
p->routes_computed = NULL;
p->routetracker = new_routetracker(p);
p->routetracker = new_routetracker(p, p);
return p;
}
@ -141,26 +142,27 @@ bool payment_update(
bool use_shadow)
{
assert(p);
struct payment_info *pinfo = &p->payment_info;
/* === Unique properties === */
// unchanged
/* === Payment attempt parameters === */
if (!amount_msat_add(&p->maxspend, p->amount, maxfee))
p->maxspend = AMOUNT_MSAT(UINT64_MAX);
p->maxdelay = maxdelay;
if (!amount_msat_add(&pinfo->maxspend, pinfo->amount, maxfee))
pinfo->maxspend = AMOUNT_MSAT(UINT64_MAX);
pinfo->maxdelay = maxdelay;
p->start_time = time_now();
p->stop_time = timeabs_add(p->start_time, time_from_sec(retryfor));
pinfo->start_time = time_now();
pinfo->stop_time = timeabs_add(pinfo->start_time, time_from_sec(retryfor));
p->final_cltv = final_cltv;
pinfo->final_cltv = final_cltv;
/* === Developer options === */
p->base_fee_penalty = base_fee_penalty_millionths / 1e6;
p->prob_cost_factor = prob_cost_factor_millionths / 1e6;
p->delay_feefactor = riskfactor_millionths / 1e6;
p->min_prob_success = min_prob_success_millionths / 1e6;
p->use_shadow = use_shadow;
pinfo->base_fee_penalty = base_fee_penalty_millionths / 1e6;
pinfo->prob_cost_factor = prob_cost_factor_millionths / 1e6;
pinfo->delay_feefactor = riskfactor_millionths / 1e6;
pinfo->min_prob_success = min_prob_success_millionths / 1e6;
pinfo->use_shadow = use_shadow;
/* === Public State === */
@ -218,7 +220,7 @@ struct amount_msat payment_delivered(const struct payment *p)
struct amount_msat payment_amount(const struct payment *p)
{
assert(p);
return p->amount;
return p->payment_info.amount;
}
struct amount_msat payment_fees(const struct payment *p)

View file

@ -4,6 +4,7 @@
#include <common/gossmap.h>
#include <plugins/libplugin.h>
#include <plugins/renepay/disabledmap.h>
#include <plugins/renepay/payment_info.h>
enum payment_status { PAYMENT_PENDING, PAYMENT_SUCCESS, PAYMENT_FAIL };
@ -14,80 +15,10 @@ struct payment {
// TODO: probably not necessary after we store all payments in a
// hashtable instead of a list
struct list_node list;
struct payment_info payment_info;
/* === Unique properties === */
/* payment_hash is unique */
struct sha256 payment_hash;
/* invstring (bolt11 or bolt12) */
const char *invstr;
/* Description and labels, if any. */
const char *description, *label;
/* payment_secret, if specified by invoice. */
struct secret *payment_secret;
/* Payment metadata, if specified by invoice. */
const u8 *payment_metadata;
/* Extracted routehints */
const struct route_info **routehints;
/* How much, what, where */
struct node_id destination;
struct amount_msat amount;
/* === Payment attempt parameters === */
/* Limits on what routes we'll accept. */
struct amount_msat maxspend;
/* Max accepted HTLC delay.*/
unsigned int maxdelay;
/* TODO new feature: Maximum number of hops */
// see common/gossip_constants.h:8:#define ROUTING_MAX_HOPS 20
// int max_num_hops;
/* We promised this in pay() output */
struct timeabs start_time;
/* We stop trying after this time is reached. */
struct timeabs stop_time;
u32 final_cltv;
/* === Developer options === */
/* Penalty for base fee */
double base_fee_penalty;
/* Conversion from prob. cost to millionths */
double prob_cost_factor;
/* prob. cost = - prob_cost_factor * log prob. */
/* Penalty for CLTV delays */
double delay_feefactor;
/* With these the effective linear fee cost is computed as
*
* linear fee cost =
* millionths
* + base_fee* base_fee_penalty
* +delay*delay_feefactor;
* */
/* The minimum acceptable prob. of success */
double min_prob_success;
/* --developer allows disabling shadow route */
bool use_shadow;
/* === Public State === */
/* TODO: these properties should be private and only changed through
* payment_ methods. */
@ -146,7 +77,7 @@ struct payment {
static inline const struct sha256 payment_hash(const struct payment *p)
{
return p->payment_hash;
return p->payment_info.payment_hash;
}
static inline size_t payment_hash64(const struct sha256 h)
@ -157,14 +88,14 @@ static inline size_t payment_hash64(const struct sha256 h)
static inline bool payment_hash_eq(const struct payment *p,
const struct sha256 h)
{
return p->payment_hash.u.u32[0] == h.u.u32[0] &&
p->payment_hash.u.u32[1] == h.u.u32[1] &&
p->payment_hash.u.u32[2] == h.u.u32[2] &&
p->payment_hash.u.u32[3] == h.u.u32[3] &&
p->payment_hash.u.u32[4] == h.u.u32[4] &&
p->payment_hash.u.u32[5] == h.u.u32[5] &&
p->payment_hash.u.u32[6] == h.u.u32[6] &&
p->payment_hash.u.u32[7] == h.u.u32[7];
return p->payment_info.payment_hash.u.u32[0] == h.u.u32[0] &&
p->payment_info.payment_hash.u.u32[1] == h.u.u32[1] &&
p->payment_info.payment_hash.u.u32[2] == h.u.u32[2] &&
p->payment_info.payment_hash.u.u32[3] == h.u.u32[3] &&
p->payment_info.payment_hash.u.u32[4] == h.u.u32[4] &&
p->payment_info.payment_hash.u.u32[5] == h.u.u32[5] &&
p->payment_info.payment_hash.u.u32[6] == h.u.u32[6] &&
p->payment_info.payment_hash.u.u32[7] == h.u.u32[7];
}
HTABLE_DEFINE_TYPE(struct payment, payment_hash, payment_hash64,

View file

@ -0,0 +1,82 @@
#ifndef LIGHTNING_PLUGINS_RENEPAY_PAYMENT_INFO_H
#define LIGHTNING_PLUGINS_RENEPAY_PAYMENT_INFO_H
/* Plain data payment information. */
#include "config.h"
#include <ccan/crypto/sha256/sha256.h>
#include <ccan/time/time.h>
#include <common/amount.h>
#include <common/node_id.h>
struct payment_info {
/* payment_hash is unique */
struct sha256 payment_hash;
/* invstring (bolt11 or bolt12) */
const char *invstr;
/* Description and labels, if any. */
const char *description, *label;
/* payment_secret, if specified by invoice. */
struct secret *payment_secret;
/* Payment metadata, if specified by invoice. */
const u8 *payment_metadata;
/* Extracted routehints */
const struct route_info **routehints;
/* How much, what, where */
struct node_id destination;
struct amount_msat amount;
/* === Payment attempt parameters === */
/* Limits on what routes we'll accept. */
struct amount_msat maxspend;
/* Max accepted HTLC delay.*/
unsigned int maxdelay;
/* TODO new feature: Maximum number of hops */
// see common/gossip_constants.h:8:#define ROUTING_MAX_HOPS 20
// int max_num_hops;
/* We promised this in pay() output */
struct timeabs start_time;
/* We stop trying after this time is reached. */
struct timeabs stop_time;
u32 final_cltv;
/* === Developer options === */
/* Penalty for base fee */
double base_fee_penalty;
/* Conversion from prob. cost to millionths */
double prob_cost_factor;
/* prob. cost = - prob_cost_factor * log prob. */
/* Penalty for CLTV delays */
double delay_feefactor;
/* With these the effective linear fee cost is computed as
*
* linear fee cost =
* millionths
* + base_fee* base_fee_penalty
* +delay*delay_feefactor;
* */
/* The minimum acceptable prob. of success */
double min_prob_success;
/* --developer allows disabling shadow route */
bool use_shadow;
};
#endif /* LIGHTNING_PLUGINS_RENEPAY_PAYMENT_INFO_H */

View file

@ -1,13 +1,12 @@
#include "config.h"
#include <plugins/renepay/route.h>
struct route *new_route(const tal_t *ctx, struct payment *payment, u32 groupid,
struct route *new_route(const tal_t *ctx, u32 groupid,
u32 partid, struct sha256 payment_hash,
struct amount_msat amount,
struct amount_msat amount_sent)
{
struct route *route = tal(ctx, struct route);
route->payment = payment;
route->key.partid = partid;
route->key.groupid = groupid;
route->key.payment_hash = payment_hash;
@ -26,18 +25,17 @@ struct route *new_route(const tal_t *ctx, struct payment *payment, u32 groupid,
/* Construct a route from a flow.
*
* @ctx: allocator
* @payment: NULL or the payment this route will point to
* @groupid, @partid, @payment_hash: unique identification keys for this route
* @final_cltv: final delay required by the payment
* @gossmap: global gossmap
* @flow: the flow to convert to route */
struct route *flow_to_route(const tal_t *ctx, struct payment *payment,
struct route *flow_to_route(const tal_t *ctx,
u32 groupid, u32 partid, struct sha256 payment_hash,
u32 final_cltv, struct gossmap *gossmap,
struct flow *flow)
{
struct route *route =
new_route(ctx, payment, groupid, partid, payment_hash,
new_route(ctx, groupid, partid, payment_hash,
AMOUNT_MSAT(0), AMOUNT_MSAT(0));
size_t pathlen = tal_count(flow->path);
@ -75,7 +73,7 @@ function_fail:
return tal_free(route);
}
struct route **flows_to_routes(const tal_t *ctx, struct payment *payment,
struct route **flows_to_routes(const tal_t *ctx,
u32 groupid, u32 partid,
struct sha256 payment_hash, u32 final_cltv,
struct gossmap *gossmap, struct flow **flows)
@ -86,7 +84,7 @@ struct route **flows_to_routes(const tal_t *ctx, struct payment *payment,
struct route **routes = tal_arr(ctx, struct route *, N);
for (size_t i = 0; i < N; i++) {
routes[i] =
flow_to_route(routes, payment, groupid, partid++,
flow_to_route(routes, groupid, partid++,
payment_hash, final_cltv, gossmap, flows[i]);
if (!routes[i])
goto function_fail;

View file

@ -49,9 +49,6 @@ struct route {
enum jsonrpc_errcode final_error;
const char *final_msg;
/* So we can be an independent object for callbacks. */
struct payment *payment;
/* Information to link this flow to a unique sendpay. */
struct routekey {
struct sha256 payment_hash;
@ -112,17 +109,17 @@ static inline bool routekey_equal(const struct route *route,
HTABLE_DEFINE_TYPE(struct route, route_get_key, routekey_hash, routekey_equal,
route_map);
struct route *new_route(const tal_t *ctx, struct payment *payment, u32 groupid,
struct route *new_route(const tal_t *ctx, u32 groupid,
u32 partid, struct sha256 payment_hash,
struct amount_msat amount,
struct amount_msat amount_sent);
struct route *flow_to_route(const tal_t *ctx, struct payment *payment,
struct route *flow_to_route(const tal_t *ctx,
u32 groupid, u32 partid, struct sha256 payment_hash,
u32 final_cltv, struct gossmap *gossmap,
struct flow *flow);
struct route **flows_to_routes(const tal_t *ctx, struct payment *payment,
struct route **flows_to_routes(const tal_t *ctx,
u32 groupid, u32 partid,
struct sha256 payment_hash, u32 final_cltv,
struct gossmap *gossmap, struct flow **flows);

View file

@ -3,56 +3,7 @@
#include <plugins/renepay/mcf.h>
#include <plugins/renepay/routebuilder.h>
static bitmap *
make_disabled_channels_bitmap(const tal_t *ctx, const struct gossmap *gossmap,
const struct chan_extra_map *chan_extra_map,
const struct short_channel_id *disabled_scids)
{
bitmap *disabled =
tal_arrz(ctx, bitmap, BITMAP_NWORDS(gossmap_max_chan_idx(gossmap)));
if (!disabled)
return NULL;
/* Disable every channel in the list of disabled scids. */
for (size_t i = 0; i < tal_count(disabled_scids); i++) {
struct gossmap_chan *c =
gossmap_find_chan(gossmap, &disabled_scids[i]);
if (c)
bitmap_set_bit(disabled, gossmap_chan_idx(gossmap, c));
}
/* Also disable every channel that we don't have in the chan_extra_map.
*/
for (struct gossmap_chan *chan = gossmap_first_chan(gossmap); chan;
chan = gossmap_next_chan(gossmap, chan)) {
const u32 chan_id = gossmap_chan_idx(gossmap, chan);
struct short_channel_id scid = gossmap_chan_scid(gossmap, chan);
struct chan_extra *ce =
chan_extra_map_get(chan_extra_map, scid);
if (!ce)
bitmap_set_bit(disabled, chan_id);
}
return disabled;
}
/* Disable all channels that lead to a disabled node. */
static bool make_disabled_nodes(const struct gossmap *gossmap,
const struct node_id *disabled_nodes,
bitmap *disabled)
{
/* Disable every channel in the list of disabled scids. */
for (size_t i = 0; i < tal_count(disabled_nodes); i++) {
const struct gossmap_node *node =
gossmap_find_node(gossmap, &disabled_nodes[i]);
for (size_t j = 0; j < node->num_chans; j++) {
int half;
const struct gossmap_chan *c =
gossmap_nth_chan(gossmap, node, j, &half);
bitmap_set_bit(disabled, gossmap_chan_idx(gossmap, c));
}
}
return true;
}
#include <stdio.h>
// static void uncertainty_commit_routes(struct uncertainty *uncertainty,
// struct route **routes)
@ -69,23 +20,13 @@ static void uncertainty_remove_routes(struct uncertainty *uncertainty,
uncertainty_remove_htlcs(uncertainty, routes[i]);
}
static void mark_chan_disabled(const struct gossmap_chan *chan,
struct short_channel_id **disabled_scids,
bitmap *disabled_bitmap,
struct gossmap *gossmap)
{
struct short_channel_id scid = gossmap_chan_scid(gossmap, chan);
tal_arr_expand(disabled_scids, scid);
bitmap_set_bit(disabled_bitmap, gossmap_chan_idx(gossmap, chan));
}
// TODO: check
/* Shave-off amounts that do not meet the liquidity constraints. Disable
* channels that produce an htlc_max bottleneck. */
static struct flow **flows_adjust_htlcmax_constraints(
const tal_t *ctx, struct flow **flows TAKES, struct gossmap *gossmap,
struct chan_extra_map *chan_extra_map,
struct short_channel_id **disabled_scids, bitmap *disabled_bitmap)
bitmap *disabled_bitmap)
{
struct flow **new_flows = tal_arr(ctx, struct flow *, 0);
enum renepay_errorcode errorcode;
@ -106,8 +47,9 @@ static struct flow **flows_adjust_htlcmax_constraints(
tal_arr_expand(&new_flows, f);
} else if (errorcode == RENEPAY_BAD_CHANNEL) {
// this is a channel that we can disable
mark_chan_disabled(bad_channel, disabled_scids,
disabled_bitmap, gossmap);
// FIXME: log this error?
bitmap_set_bit(disabled_bitmap,
gossmap_chan_idx(gossmap, bad_channel));
continue;
} else {
// we had an unexpected error
@ -134,7 +76,7 @@ function_fail:
static struct flow **flows_adjust_htlcmin_constraints(
const tal_t *ctx, struct flow **flows TAKES, struct gossmap *gossmap,
struct chan_extra_map *chan_extra_map,
struct short_channel_id **disabled_scids, bitmap *disabled_bitmap)
bitmap *disabled_bitmap)
{
struct flow **new_flows = tal_arr(ctx, struct flow *, 0);
enum renepay_errorcode errorcode;
@ -155,8 +97,9 @@ static struct flow **flows_adjust_htlcmin_constraints(
tal_arr_expand(&new_flows, f);
} else if (errorcode == RENEPAY_BAD_CHANNEL) {
// this is a channel that we can disable
mark_chan_disabled(bad_channel, disabled_scids,
disabled_bitmap, gossmap);
// FIXME: log this error?
bitmap_set_bit(disabled_bitmap,
gossmap_chan_idx(gossmap, bad_channel));
continue;
} else {
// we had an unexpected error
@ -179,16 +122,23 @@ function_fail:
}
/* Routes are computed and saved in the payment for later use. */
struct route **get_routes(const tal_t *ctx, struct payment *payment,
struct route **get_routes(const tal_t *ctx,
struct payment_info *payment_info,
const struct node_id *source,
const struct node_id *destination,
struct gossmap *gossmap, struct uncertainty *uncertainty,
struct gossmap *gossmap,
struct uncertainty *uncertainty,
struct disabledmap *disabledmap,
struct amount_msat amount_to_deliver,
const u32 final_cltv, struct amount_msat feebudget,
struct amount_msat feebudget,
enum jsonrpc_errcode *ecode, const char **fail)
u64 *next_partid,
u64 groupid,
enum jsonrpc_errcode *ecode,
const char **fail)
{
assert(gossmap);
assert(uncertainty);
@ -196,17 +146,14 @@ struct route **get_routes(const tal_t *ctx, struct payment *payment,
const tal_t *this_ctx = tal(ctx, tal_t);
struct route **routes = tal_arr(ctx, struct route *, 0);
double probability_budget = payment->min_prob_success;
double delay_feefactor = payment->delay_feefactor;
const double base_fee_penalty = payment->base_fee_penalty;
const double prob_cost_factor = payment->prob_cost_factor;
const unsigned int maxdelay = payment->maxdelay;
double probability_budget = payment_info->min_prob_success;
double delay_feefactor = payment_info->delay_feefactor;
const double base_fee_penalty = payment_info->base_fee_penalty;
const double prob_cost_factor = payment_info->prob_cost_factor;
const unsigned int maxdelay = payment_info->maxdelay;
bitmap *disabled_bitmap = make_disabled_channels_bitmap(
this_ctx, gossmap, uncertainty->chan_extra_map,
payment->disabled_scids);
make_disabled_nodes(gossmap, payment->disabled_nodes, disabled_bitmap);
bitmap *disabled_bitmap =
tal_disabledmap_get_bitmap(this_ctx, disabledmap, gossmap);
if (!disabled_bitmap) {
if (ecode)
@ -217,6 +164,18 @@ struct route **get_routes(const tal_t *ctx, struct payment *payment,
goto function_fail;
}
/* Also disable every channel that we don't have in the chan_extra_map.
*/
for (struct gossmap_chan *chan = gossmap_first_chan(gossmap); chan;
chan = gossmap_next_chan(gossmap, chan)) {
const u32 chan_id = gossmap_chan_idx(gossmap, chan);
struct short_channel_id scid = gossmap_chan_scid(gossmap, chan);
struct chan_extra *ce =
chan_extra_map_get(uncertainty->chan_extra_map, scid);
if (!ce)
bitmap_set_bit(disabled_bitmap, chan_id);
}
const struct gossmap_node *src, *dst;
src = gossmap_find_node(gossmap, source);
if (!src) {
@ -241,13 +200,14 @@ struct route **get_routes(const tal_t *ctx, struct payment *payment,
while (!amount_msat_zero(amount_to_deliver)) {
printf("amount to deliver: %s\n", fmt_amount_msat(this_ctx, amount_to_deliver));
/* TODO: choose an algorithm, could be something like
* payment->algorithm, that we set up based on command line
* options and that can be changed according to some conditions
* met during the payment process, eg. add "select_solver" pay
* mod. */
/* TODO: use uncertainty instead of chan_extra */
/* TODO: shall we add to possibility to blacklist nodes? */
/* Min. Cost Flow algorithm to find optimal flows. */
struct flow **flows =
@ -278,7 +238,7 @@ struct route **get_routes(const tal_t *ctx, struct payment *payment,
flows = flows_adjust_htlcmax_constraints(
this_ctx, take(flows), gossmap,
uncertainty_get_chan_extra_map(uncertainty),
&payment->disabled_scids, disabled_bitmap);
disabled_bitmap);
if (!flows) {
if (ecode)
*ecode = PAY_ROUTE_NOT_FOUND;
@ -294,7 +254,7 @@ struct route **get_routes(const tal_t *ctx, struct payment *payment,
flows = flows_adjust_htlcmin_constraints(
this_ctx, take(flows), gossmap,
uncertainty_get_chan_extra_map(uncertainty),
&payment->disabled_scids, disabled_bitmap);
disabled_bitmap);
if (!flows) {
if (ecode)
*ecode = PAY_ROUTE_NOT_FOUND;
@ -335,7 +295,7 @@ struct route **get_routes(const tal_t *ctx, struct payment *payment,
/* Check the CLTV delay */
/* TODO: review this, only flows with non-zero amounts */
const u64 delay = flows_worst_delay(flows) + final_cltv;
const u64 delay = flows_worst_delay(flows) + payment_info->final_cltv;
if (delay > maxdelay) {
/* FIXME: What is a sane limit? */
if (delay_feefactor > 1000) {
@ -386,14 +346,14 @@ struct route **get_routes(const tal_t *ctx, struct payment *payment,
// TODO check ownership of these routes
for (size_t i = 0; i < tal_count(flows); i++) {
struct route *r = flow_to_route(
ctx, payment, payment->groupid,
payment->next_partid, payment->payment_hash,
final_cltv, gossmap, flows[i]);
ctx, groupid,
*next_partid, payment_info->payment_hash,
payment_info->final_cltv, gossmap, flows[i]);
if (!r) {
/* TODO: what could have gone wrong? */
continue;
}
payment->next_partid++;
(*next_partid)++;
uncertainty_commit_htlcs(uncertainty, r);
tal_arr_expand(&routes, r);

View file

@ -4,19 +4,27 @@
#include "config.h"
#include <ccan/tal/tal.h>
#include <common/gossmap.h>
#include <plugins/renepay/payment.h>
#include <plugins/renepay/disabledmap.h>
#include <plugins/renepay/payment_info.h>
#include <plugins/renepay/route.h>
#include <plugins/renepay/uncertainty.h>
struct route **get_routes(const tal_t *ctx, struct payment *payment,
struct route **get_routes(const tal_t *ctx,
struct payment_info *payment_info,
const struct node_id *source,
const struct node_id *destination,
struct gossmap *gossmap, struct uncertainty *uncertainty,
struct gossmap *gossmap,
struct uncertainty *uncertainty,
struct disabledmap *disabledmap,
struct amount_msat amount_to_deliver,
const u32 final_cltv, struct amount_msat feebudget,
struct amount_msat feebudget,
u64 *next_partid,
u64 groupid,
enum jsonrpc_errcode *ecode, const char **fail);
enum jsonrpc_errcode *ecode,
const char **fail);
#endif /* LIGHTNING_PLUGINS_RENEPAY_ROUTEBUILDER_H */

View file

@ -15,6 +15,7 @@ enum node_type {
struct routefail {
struct command *cmd;
struct payment *payment;
struct route *route;
};
@ -24,7 +25,18 @@ static struct command_result *handle_failure(struct routefail *r);
struct command_result *routefail_start(const tal_t *ctx, struct route *route,
struct command *cmd)
{
assert(route);
struct routefail *r = tal(ctx, struct routefail);
struct payment *payment =
payment_map_get(pay_plugin->payment_map, route->key.payment_hash);
if (payment == NULL)
plugin_err(pay_plugin->plugin,
"%s: payment with hash %s not found.",
__PRETTY_FUNCTION__,
fmt_sha256(tmpctx, &route->key.payment_hash));
r->payment = payment;
r->route = route;
r->cmd = cmd;
assert(route->result);
@ -36,7 +48,7 @@ static struct command_result *routefail_end(struct routefail *r)
/* Notify the tracker that route has failed and routefail have completed
* handling all possible errors cases. */
struct command *cmd = r->cmd;
route_failure_register(r->route);
route_failure_register(r->payment->routetracker, r->route);
tal_free(r);
return notification_handled(cmd);
}
@ -109,13 +121,16 @@ static struct command_result *update_gossip_failure(struct command *cmd UNUSED,
const jsmntok_t *result,
struct routefail *r)
{
assert(r);
assert(r->payment);
/* FIXME it might be too strong assumption that erring_channel should
* always be present here, but at least the documentation for
* waitsendpay says it is present in the case of error. */
assert(r->route->result->erring_channel);
payment_disable_chan(
r->route->payment, *r->route->result->erring_channel, LOG_INFORM,
r->payment, *r->route->result->erring_channel, LOG_INFORM,
"addgossip failed (%.*s)", json_tok_full_len(result),
json_tok_full(buf, result));
return update_gossip_done(cmd, buf, result, r);
@ -198,10 +213,10 @@ static struct command_result *handle_failure(struct routefail *r)
assert(route);
struct payment_result *result = route->result;
assert(result);
struct payment *payment = route->payment;
struct payment *payment = r->payment;
assert(payment);
u32 path_len = 0;
int path_len = 0;
if (route->hops)
path_len = tal_count(route->hops);
@ -248,7 +263,7 @@ static struct command_result *handle_failure(struct routefail *r)
/* we disable the next node in the hop */
assert(*result->erring_index < path_len);
payment_disable_node(
route->payment,
payment,
route->hops[*result->erring_index].node_id, LOG_DBG,
"received %s from previous hop",
onion_wire_name(result->failcode));
@ -286,7 +301,7 @@ static struct command_result *handle_failure(struct routefail *r)
result->failcode,
onion_wire_name(result->failcode));
} else {
payment_disable_node(route->payment,
payment_disable_node(payment,
*result->erring_node, LOG_INFORM,
"received error %s",
onion_wire_name(result->failcode));
@ -316,7 +331,7 @@ static struct command_result *handle_failure(struct routefail *r)
} else {
assert(result->erring_channel);
payment_disable_chan(
route->payment, *result->erring_channel, LOG_INFORM,
payment, *result->erring_channel, LOG_INFORM,
"%s", onion_wire_name(result->failcode));
}
break;
@ -335,7 +350,7 @@ static struct command_result *handle_failure(struct routefail *r)
result->failcode,
onion_wire_name(result->failcode));
payment_disable_node(route->payment,
payment_disable_node(payment,
*result->erring_node, LOG_INFORM,
"received error %s",
onion_wire_name(result->failcode));
@ -367,7 +382,7 @@ static struct command_result *handle_failure(struct routefail *r)
* information and try again. To avoid hitting this
* error again with the same channel we flag it. */
assert(result->erring_channel);
payment_warn_chan(route->payment,
payment_warn_chan(payment,
*result->erring_channel, LOG_INFORM,
"received error %s",
onion_wire_name(result->failcode));
@ -401,7 +416,13 @@ static struct command_result *handle_failure(struct routefail *r)
/* Update the knowledge in the uncertaity network. */
if (route->hops) {
assert(last_good_channel < path_len);
if(last_good_channel >= path_len)
{
plugin_err(pay_plugin->plugin,
"last_good_channel (%d) >= path_len (%d)",
last_good_channel,
path_len);
}
/* All channels before the erring node could forward the
* payment. */

View file

@ -6,9 +6,23 @@
#include <plugins/renepay/routefail.h>
#include <plugins/renepay/routetracker.h>
struct routetracker *new_routetracker(const tal_t *ctx)
static struct payment *route_get_payment_verify(struct route *route)
{
struct payment *payment =
payment_map_get(pay_plugin->payment_map, route->key.payment_hash);
if (!payment)
plugin_err(pay_plugin->plugin,
"%s: no payment associated with routekey %s",
__PRETTY_FUNCTION__,
fmt_routekey(tmpctx, &route->key));
return payment;
}
struct routetracker *new_routetracker(const tal_t *ctx, struct payment *payment)
{
struct routetracker *rt = tal(ctx, struct routetracker);
rt->payment = payment;
rt->sent_routes = tal(rt, struct route_map);
route_map_init(rt->sent_routes);
@ -41,23 +55,25 @@ static void routetracker_add_to_final(struct routetracker *routetracker,
tal_arr_expand(&routetracker->finalized_routes, route);
tal_steal(routetracker, route);
}
static void route_success_register(struct route *route)
static void route_success_register(struct routetracker *routetracker,
struct route *route)
{
routetracker_add_to_final(route->payment->routetracker, route);
routetracker_add_to_final(routetracker, route);
}
void route_failure_register(struct route *route)
void route_failure_register(struct routetracker *routetracker,
struct route *route)
{
routetracker_add_to_final(route->payment->routetracker, route);
routetracker_add_to_final(routetracker, route);
}
static void route_sent_register(struct route *route)
static void route_sent_register(struct routetracker *routetracker,
struct route *route)
{
struct routetracker *routetracker = route->payment->routetracker;
route_map_add(routetracker->sent_routes, route);
tal_steal(routetracker, route);
}
static void route_sendpay_fail(struct route *route TAKES)
static void route_sendpay_fail(struct routetracker *routetracker,
struct route *route TAKES)
{
struct routetracker *routetracker = route->payment->routetracker;
if (!route_map_del(routetracker->sent_routes, route))
plugin_log(pay_plugin->plugin, LOG_UNUSUAL,
"%s: route (%s) is not marked as sent",
@ -72,14 +88,14 @@ static void route_sendpay_fail(struct route *route TAKES)
* - after a sendpay is accepted,
* - or after listsendpays reveals some pending route that we didn't
* previously know about. */
void route_pending_register(const struct route *route)
void route_pending_register(struct routetracker *routetracker,
const struct route *route)
{
assert(route);
struct payment *payment = route->payment;
assert(routetracker);
struct payment *payment = routetracker->payment;
assert(payment);
assert(payment->groupid == route->key.groupid);
struct routetracker *routetracker = payment->routetracker;
assert(routetracker);
/* we already keep track of this route */
if (route_map_get(routetracker->pending_routes, &route->key))
@ -110,14 +126,15 @@ void route_pending_register(const struct route *route)
}
}
static void route_result_collected(struct route *route TAKES)
static void route_result_collected(struct routetracker *routetracker,
struct route *route TAKES)
{
assert(route);
assert(routetracker);
assert(route->result);
assert(route->payment);
struct payment *payment = route->payment;
assert(payment->groupid == route->key.groupid);
struct payment *payment = routetracker->payment;
assert(payment);
if (route->result->status == SENDPAY_FAILED) {
if (!amount_msat_sub(&payment->total_delivering,
@ -142,7 +159,8 @@ static struct command_result *sendpay_done(struct command *cmd,
struct route *route)
{
assert(route);
route_pending_register(route);
struct payment *payment = route_get_payment_verify(route);
route_pending_register(payment->routetracker, route);
return command_still_pending(cmd);
}
@ -156,8 +174,7 @@ static struct command_result *sendpay_failed(struct command *cmd,
struct route *route)
{
assert(route);
assert(route->payment);
struct payment *payment = route->payment;
struct payment *payment = route_get_payment_verify(route);
enum jsonrpc_errcode errcode;
const char *msg;
@ -187,7 +204,7 @@ static struct command_result *sendpay_failed(struct command *cmd,
payment_disable_chan(payment, route->hops[0].scid, LOG_INFORM,
"sendpay didn't like first hop: %s", msg);
route_sendpay_fail(take(route));
route_sendpay_fail(payment->routetracker, take(route));
return command_still_pending(cmd);
}
@ -235,21 +252,22 @@ void payment_collect_results(struct payment *payment,
tal_strdup(tmpctx, r->final_msg);
}
}
route_result_collected(take(r));
route_result_collected(routetracker, take(r));
}
tal_resize(&routetracker->finalized_routes, 0);
}
struct command_result *route_sendpay_request(struct command *cmd,
struct route *route)
struct route *route,
struct payment *payment)
{
struct out_req *req =
jsonrpc_request_start(pay_plugin->plugin, cmd, "sendpay",
sendpay_done, sendpay_failed, route);
json_add_route(req->js, route);
json_add_route(req->js, route, payment);
route_sent_register(route);
route_sent_register(payment->routetracker, route);
return send_outreq(pay_plugin->plugin, req);
}
@ -362,6 +380,6 @@ struct command_result *notification_sendpay_success(struct command *cmd,
// FIXME: what happens when several success notification arrive for the
// same payment? Even after the payment has been resolved.
route_success_register(route);
route_success_register(payment->routetracker, route);
return notification_handled(cmd);
}

View file

@ -7,12 +7,13 @@
#include <plugins/renepay/route.h>
struct routetracker{
struct payment *payment;
struct route_map *sent_routes;
struct route_map *pending_routes;
struct route **finalized_routes;
};
struct routetracker *new_routetracker(const tal_t *ctx);
struct routetracker *new_routetracker(const tal_t *ctx, struct payment *payment);
// bool routetracker_is_ready(const struct routetracker *routetracker);
void routetracker_cleanup(struct routetracker *routetracker);
size_t routetracker_count_sent(struct routetracker *routetracker);
@ -29,11 +30,13 @@ void payment_collect_results(struct payment *payment,
/* Announce that this route is pending and needs to be kept in the waiting list
* for notifications. */
void route_pending_register(const struct route *route);
void route_pending_register(struct routetracker *routetracker,
const struct route *route);
/* Sends a sendpay request for this route. */
struct command_result *route_sendpay_request(struct command *cmd,
struct route *route);
struct route *route,
struct payment *payment);
struct command_result *notification_sendpay_failure(struct command *cmd,
const char *buf,
@ -44,7 +47,8 @@ struct command_result *notification_sendpay_success(struct command *cmd,
const jsmntok_t *params);
/* Notify the tracker that this route has failed. */
void route_failure_register(struct route *route);
void route_failure_register(struct routetracker *routetracker,
struct route *route);
// FIXME: double-check that we actually get one notification for each sendpay,
// ie. that after some time we don't have yet pending sendpays for old failed or