mirror of
https://github.com/ElementsProject/lightning.git
synced 2025-03-26 20:30:59 +01:00
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:
parent
ca2b4e54ae
commit
da00cae30b
14 changed files with 363 additions and 321 deletions
|
@ -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 \
|
||||
|
|
|
@ -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);
|
||||
|
||||
}
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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,
|
||||
|
|
82
plugins/renepay/payment_info.h
Normal file
82
plugins/renepay/payment_info.h
Normal 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 */
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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. */
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Add table
Reference in a new issue