renepay: merge struct renepay and struct payment into one.

There are a few fields in `struct renepay` which are genuinely
transient, but it makes the code much harder to follow than simply
having a single structure.

More cleanups will follow, but this is the minimal set.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
This commit is contained in:
Rusty Russell 2023-08-10 09:31:08 +09:30
parent 6d7cd1e729
commit 3b8217bd72
7 changed files with 194 additions and 271 deletions

View file

@ -32,9 +32,9 @@
static struct pay_plugin the_pay_plugin;
struct pay_plugin * const pay_plugin = &the_pay_plugin;
static void timer_kick(struct renepay * renepay);
static void timer_kick(struct payment *payment);
static struct command_result *try_paying(struct command *cmd,
struct renepay * renepay,
struct payment *payment,
bool first_time);
void amount_msat_accumulate_(struct amount_msat *dst,
@ -126,56 +126,54 @@ static const char *init(struct plugin *p,
}
static void renepay_settimer(struct renepay * renepay)
static void payment_settimer(struct payment *payment)
{
renepay->rexmit_timer = tal_free(renepay->rexmit_timer);
renepay->rexmit_timer = plugin_timer(
payment->rexmit_timer = tal_free(payment->rexmit_timer);
payment->rexmit_timer = plugin_timer(
pay_plugin->plugin,
time_from_msec(TIMER_COLLECT_FAILURES_MSEC),
timer_kick, renepay);
timer_kick, payment);
}
/* Happens when timer goes off, but also works to arm timer if nothing to do */
static void timer_kick(struct renepay * renepay)
static void timer_kick(struct payment *payment)
{
struct payment * const p = renepay->payment;
plugin_log(pay_plugin->plugin,LOG_DBG,"calling %s",__PRETTY_FUNCTION__);
switch(p->status)
switch (payment->status)
{
/* Some flows succeeded, we finish the payment. */
case PAYMENT_SUCCESS:
plugin_log(pay_plugin->plugin,LOG_DBG,"status is PAYMENT_SUCCESS");
renepay_success(renepay);
payment_success(payment);
break;
/* Some flows failed, we retry. */
case PAYMENT_FAIL:
plugin_log(pay_plugin->plugin,LOG_DBG,"status is PAYMENT_FAIL");
payment_assert_delivering_incomplete(p);
try_paying(renepay->cmd,renepay,/* always try even if prob is low */ true);
payment_assert_delivering_incomplete(payment);
try_paying(payment->cmd,payment,/* always try even if prob is low */ true);
break;
/* Nothing has returned yet, we have to wait. */
case PAYMENT_PENDING:
plugin_log(pay_plugin->plugin,LOG_DBG,"status is PAYMENT_PENDING");
payment_assert_delivering_all(p);
renepay_settimer(renepay);
payment_assert_delivering_all(payment);
payment_settimer(payment);
break;
}
}
/* Sometimes we don't know exactly who to blame... */
static struct command_result *handle_unhandleable_error(struct renepay * renepay,
static struct command_result *handle_unhandleable_error(struct payment *payment,
struct pay_flow *flow,
const char *what)
{
struct payment * const p = renepay->payment;
plugin_log(pay_plugin->plugin,LOG_DBG,"calling %s",__PRETTY_FUNCTION__);
size_t n = tal_count(flow);
/* We got a mangled reply. We don't know who to penalize! */
debug_paynote(p, "%s on route %s", what, flow_path_to_str(tmpctx, flow));
debug_paynote(payment, "%s on route %s", what, flow_path_to_str(tmpctx, flow));
// TODO(eduardo): does LOG_BROKEN finish the plugin execution?
plugin_log(pay_plugin->plugin, LOG_BROKEN,
@ -185,7 +183,7 @@ static struct command_result *handle_unhandleable_error(struct renepay * renepay
if (n == 1)
{
payflow_fail(flow);
return renepay_fail(renepay, PAY_UNPARSEABLE_ONION,
return payment_fail(payment, PAY_UNPARSEABLE_ONION,
"Got %s from the destination", what);
}
/* FIXME: check chan_extra_map, since we might have succeeded though
@ -199,8 +197,8 @@ static struct command_result *handle_unhandleable_error(struct renepay * renepay
/* Assume it's not the destination */
n = pseudorand(n-1);
tal_arr_expand(&renepay->disabled, flow->path_scids[n]);
debug_paynote(p, "... eliminated %s",
tal_arr_expand(&payment->disabled, flow->path_scids[n]);
debug_paynote(payment, "... eliminated %s",
type_to_string(tmpctx, struct short_channel_id,
&flow->path_scids[n]));
return NULL;
@ -219,13 +217,13 @@ static struct command_result *addgossip_done(struct command *cmd,
struct addgossip *adg)
{
plugin_log(pay_plugin->plugin,LOG_DBG,"calling %s",__PRETTY_FUNCTION__);
struct renepay * renepay = adg->flow->payment->renepay;
struct payment * payment = adg->flow->payment;
/* Release this: if it's the last flow we'll retry immediately */
payflow_fail(adg->flow);
tal_free(adg);
renepay_settimer(renepay);
payment_settimer(payment);
return command_still_pending(cmd);
}
@ -236,14 +234,13 @@ static struct command_result *addgossip_failure(struct command *cmd,
struct addgossip *adg)
{
struct payment * payment = adg->flow->payment;
plugin_log(pay_plugin->plugin,LOG_DBG,"calling %s",__PRETTY_FUNCTION__);
struct payment * p = adg->flow->payment;
struct renepay * renepay = p->renepay;
debug_paynote(p, "addgossip failed, removing channel %s (%.*s)",
debug_paynote(payment, "addgossip failed, removing channel %s (%.*s)",
type_to_string(tmpctx, struct short_channel_id, &adg->scid),
err->end - err->start, buf + err->start);
tal_arr_expand(&renepay->disabled, adg->scid);
tal_arr_expand(&payment->disabled, adg->scid);
return addgossip_done(cmd, buf, err, adg);
}
@ -254,8 +251,7 @@ static struct command_result *submit_update(struct command *cmd,
struct short_channel_id errscid)
{
plugin_log(pay_plugin->plugin,LOG_DBG,"calling %s",__PRETTY_FUNCTION__);
struct payment * p = flow->payment;
struct renepay * renepay = p->renepay;
struct payment *payment = flow->payment;
struct out_req *req;
struct addgossip *adg = tal(cmd, struct addgossip);
@ -264,10 +260,9 @@ static struct command_result *submit_update(struct command *cmd,
adg->scid = errscid;
adg->flow = flow;
/* Disable re-xmit until this returns */
renepay->rexmit_timer
= tal_free(renepay->rexmit_timer);
payment->rexmit_timer = tal_free(payment->rexmit_timer);
debug_paynote(p, "... extracted channel_update, telling gossipd");
debug_paynote(payment, "... extracted channel_update, telling gossipd");
plugin_log(pay_plugin->plugin, LOG_DBG, "(update = %s)", tal_hex(tmpctx, update));
req = jsonrpc_request_start(pay_plugin->plugin, NULL, "addgossip",
@ -357,13 +352,12 @@ static struct command_result *flow_sendpay_failed(struct command *cmd,
{
plugin_log(pay_plugin->plugin,LOG_DBG,"calling %s",__PRETTY_FUNCTION__);
struct payment *p = flow->payment;
debug_assert(p);
struct renepay * renepay = p->renepay;
debug_assert(renepay);
struct payment *payment = flow->payment;
debug_assert(payment);
/* This is a fail. */
payment_fail(p);
if (payment->status != PAYMENT_SUCCESS)
payment->status=PAYMENT_FAIL;
u64 errcode;
const jsmntok_t *msg = json_get_member(buf, err, "message");
@ -376,13 +370,13 @@ static struct command_result *flow_sendpay_failed(struct command *cmd,
plugin_err(cmd->plugin, "Strange error from sendpay: %.*s",
json_tok_full_len(err), json_tok_full(buf, err));
debug_paynote(p,
debug_paynote(payment,
"sendpay didn't like first hop, eliminated: %.*s",
msg->end - msg->start, buf + msg->start);
/* There is no new knowledge from this kind of failure.
* We just disable this scid. */
tal_arr_expand(&renepay->disabled, flow->path_scids[0]);
tal_arr_expand(&payment->disabled, flow->path_scids[0]);
payflow_fail(flow);
return command_still_pending(cmd);
@ -391,11 +385,9 @@ static struct command_result *flow_sendpay_failed(struct command *cmd,
static struct command_result *
sendpay_flows(struct command *cmd,
struct renepay * renepay,
struct payment *p,
struct pay_flow **flows STEALS)
{
struct payment * const p = renepay->payment;
plugin_log(pay_plugin->plugin,LOG_DBG,"calling %s",__PRETTY_FUNCTION__);
debug_paynote(p, "Sending out batch of %zu payments", tal_count(flows));
@ -476,44 +468,43 @@ sendpay_flows(struct command *cmd,
tal_free(flows);
/* Get ready to process replies */
renepay_settimer(renepay);
payment_settimer(p);
return command_still_pending(cmd);
}
static struct command_result *try_paying(struct command *cmd,
struct renepay *renepay,
struct payment *payment,
bool first_time)
{
struct payment * const p = renepay->payment;
plugin_log(pay_plugin->plugin,LOG_DBG,"calling %s",__PRETTY_FUNCTION__);
struct amount_msat feebudget, fees_spent, remaining;
renepay->payment->status=PAYMENT_PENDING;
if (time_after(time_now(), p->stop_time))
return renepay_fail(renepay, PAY_STOPPED_RETRYING, "Timed out");
payment->status = PAYMENT_PENDING;
if (time_after(time_now(), payment->stop_time))
return payment_fail(payment, PAY_STOPPED_RETRYING, "Timed out");
/* Total feebudget */
if (!amount_msat_sub(&feebudget, p->maxspend, p->amount))
if (!amount_msat_sub(&feebudget, payment->maxspend, payment->amount))
{
plugin_err(pay_plugin->plugin,
"%s (line %d) could not substract maxspend=%s and amount=%s.",
__PRETTY_FUNCTION__,
__LINE__,
type_to_string(tmpctx, struct amount_msat, &p->maxspend),
type_to_string(tmpctx, struct amount_msat, &p->amount));
type_to_string(tmpctx, struct amount_msat, &payment->maxspend),
type_to_string(tmpctx, struct amount_msat, &payment->amount));
}
/* Fees spent so far */
if (!amount_msat_sub(&fees_spent, p->total_sent, p->total_delivering))
if (!amount_msat_sub(&fees_spent, payment->total_sent, payment->total_delivering))
{
plugin_err(pay_plugin->plugin,
"%s (line %d) could not substract total_sent=%s and total_delivering=%s.",
__PRETTY_FUNCTION__,
__LINE__,
type_to_string(tmpctx, struct amount_msat, &p->total_sent),
type_to_string(tmpctx, struct amount_msat, &p->total_delivering));
type_to_string(tmpctx, struct amount_msat, &payment->total_sent),
type_to_string(tmpctx, struct amount_msat, &payment->total_delivering));
}
/* Remaining fee budget. */
@ -528,14 +519,14 @@ static struct command_result *try_paying(struct command *cmd,
}
/* How much are we still trying to send? */
if (!amount_msat_sub(&remaining, p->amount, p->total_delivering))
if (!amount_msat_sub(&remaining, payment->amount, payment->total_delivering))
{
plugin_err(pay_plugin->plugin,
"%s (line %d) could not substract amount=%s and total_delivering=%s.",
__PRETTY_FUNCTION__,
__LINE__,
type_to_string(tmpctx, struct amount_msat, &p->amount),
type_to_string(tmpctx, struct amount_msat, &p->total_delivering));
type_to_string(tmpctx, struct amount_msat, &payment->amount),
type_to_string(tmpctx, struct amount_msat, &payment->total_delivering));
}
// plugin_log(pay_plugin->plugin,LOG_DBG,fmt_chan_extra_map(tmpctx,pay_plugin->chan_extra_map));
@ -544,9 +535,9 @@ static struct command_result *try_paying(struct command *cmd,
/* We let this return an unlikely path, as it's better to try once
* than simply refuse. Plus, models are not truth! */
gossmap_apply_localmods(pay_plugin->gossmap, renepay->local_gossmods);
gossmap_apply_localmods(pay_plugin->gossmap, payment->local_gossmods);
struct pay_flow **pay_flows = get_payflows(
renepay,
payment,
remaining, feebudget,
/* would you accept unlikely
@ -554,46 +545,59 @@ static struct command_result *try_paying(struct command *cmd,
true,
/* is entire payment? */
amount_msat_eq(p->total_delivering, AMOUNT_MSAT(0)),
amount_msat_eq(payment->total_delivering, AMOUNT_MSAT(0)),
&err_msg);
gossmap_remove_localmods(pay_plugin->gossmap, renepay->local_gossmods);
gossmap_remove_localmods(pay_plugin->gossmap, payment->local_gossmods);
// plugin_log(pay_plugin->plugin,LOG_DBG,"get_payflows produced %s",fmt_payflows(tmpctx,pay_flows));
/* MCF cannot find a feasible route, we stop. */
if (!pay_flows)
{
return renepay_fail(renepay, PAY_ROUTE_NOT_FOUND,
return payment_fail(payment, PAY_ROUTE_NOT_FOUND,
"Failed to find a route, %s",
err_msg);
}
/* Now begin making payments */
return sendpay_flows(cmd, renepay, pay_flows);
return sendpay_flows(cmd, payment, pay_flows);
}
static void destroy_cmd_payment_ptr(struct command *cmd,
struct payment *payment)
{
assert(payment->cmd == cmd);
payment->cmd = NULL;
}
static struct command_result *listpeerchannels_done(
struct command *cmd,
const char *buf,
const jsmntok_t *result,
struct renepay *renepay)
struct payment *payment)
{
plugin_log(pay_plugin->plugin,LOG_DBG,"calling %s",__PRETTY_FUNCTION__);
if (!uncertainty_network_update_from_listpeerchannels(
pay_plugin->chan_extra_map,
pay_plugin->my_id,
renepay,
payment,
buf,
result))
return renepay_fail(renepay,LIGHTNINGD,
return command_fail(cmd, LIGHTNINGD,
"listpeerchannels malformed: %.*s",
json_tok_full_len(result),
json_tok_full(buf, result));
// TODO(eduardo): check that there won't be a prob. cost associated with
// any gossmap local chan. The same way there aren't fees to pay for my
// local channels.
return try_paying(cmd, renepay, true);
/* From now on, we keep a record of the payment, so persist it beyond this cmd. */
tal_steal(pay_plugin->plugin, payment);
/* When we terminate cmd for any reason, clear it from payment so we don't do it again. */
tal_add_destructor2(cmd, destroy_cmd_payment_ptr, payment);
return try_paying(cmd, payment, true);
}
@ -685,10 +689,9 @@ payment_listsendpays_previous(
struct command *cmd,
const char *buf,
const jsmntok_t *result,
struct renepay * renepay)
struct payment * payment)
{
debug_info("calling %s",__PRETTY_FUNCTION__);
struct payment * p = renepay->payment;
size_t i;
const jsmntok_t *t, *arr, *err;
@ -841,25 +844,23 @@ payment_listsendpays_previous(
json_add_string(ret, "status", "complete");
json_add_amount_msat(ret, "amount_msat", complete_msat);
json_add_amount_msat(ret, "amount_sent_msat",complete_sent);
json_add_node_id(ret, "destination", &p->destination);
json_add_sha256(ret, "payment_hash", &p->payment_hash);
json_add_node_id(ret, "destination", &payment->destination);
json_add_sha256(ret, "payment_hash", &payment->payment_hash);
json_add_u32(ret, "created_at", complete_created_at);
json_add_num(ret, "parts", complete_parts);
/* This payment was already completed, we don't keep record of
* it twice. */
renepay->payment = tal_free(renepay->payment);
* it twice: payment will be freed with cmd */
return command_finished(cmd, ret);
} else if (pending) {
assert(last_pending_group_id!=INVALID_ID);
assert(first_pending_group_id!=INVALID_ID);
p->groupid = last_pending_group_id;
renepay->next_partid = last_pending_partid+1;
payment->groupid = last_pending_group_id;
payment->next_partid = last_pending_partid+1;
p->total_sent = pending_sent;
p->total_delivering = pending_msat;
payment->total_sent = pending_sent;
payment->total_delivering = pending_msat;
plugin_log(pay_plugin->plugin,LOG_DBG,
"There are pending sendpays to this invoice. "
@ -867,31 +868,29 @@ payment_listsendpays_previous(
"delivering = %s, "
"last_partid = %"PRIu64,
last_pending_group_id,
type_to_string(tmpctx,struct amount_msat,&p->total_delivering),
type_to_string(tmpctx,struct amount_msat,&payment->total_delivering),
last_pending_partid);
if( first_pending_group_id != last_pending_group_id)
{
/* At least two pending groups for the same invoice,
* this is weird, we better stop. */
renepay->payment = tal_free(renepay->payment);
return renepay_fail(renepay, PAY_IN_PROGRESS,
return command_fail(cmd, PAY_IN_PROGRESS,
"Payment is pending by some other request.");
}
if(amount_msat_greater_eq(p->total_delivering,p->amount))
if(amount_msat_greater_eq(payment->total_delivering,payment->amount))
{
/* Pending payment already pays the full amount, we
* better stop. */
renepay->payment = tal_free(renepay->payment);
return renepay_fail(renepay, PAY_IN_PROGRESS,
return command_fail(cmd, PAY_IN_PROGRESS,
"Payment is pending with full amount already commited");
}
}else
{
/* There are no pending nor completed sendpays, get me the last
* sendpay group. */
p->groupid = (last_group==INVALID_ID ? 1 : (last_group+1)) ;
renepay->next_partid=1;
payment->groupid = (last_group==INVALID_ID ? 1 : (last_group+1)) ;
payment->next_partid=1;
}
@ -899,7 +898,7 @@ payment_listsendpays_previous(
/* Get local capacities... */
req = jsonrpc_request_start(cmd->plugin, cmd, "listpeerchannels",
listpeerchannels_done,
listpeerchannels_done, renepay);
listpeerchannels_done, payment);
return send_outreq(cmd->plugin, req);
}
@ -1117,9 +1116,12 @@ static struct command_result *json_pay(struct command *cmd,
*use_shadow = 1;
#endif
/* renepay is bound to the command, if the command finishes renepay is
* freed. */
struct renepay * renepay = renepay_new(cmd,
/* Payment is allocated off cmd to start, in case we fail cmd
* (e.g. already in progress, already succeeded). Once it's
* actually started, it persists beyond the command, so we
* tal_steal. */
struct payment *payment = payment_new(cmd,
cmd,
take(invstr),
take(label),
take(description),
@ -1138,14 +1140,10 @@ static struct command_result *json_pay(struct command *cmd,
*riskfactor_millionths,
*min_prob_success_millionths,
use_shadow);
tal_add_destructor2(renepay,
renepay_cleanup,
pay_plugin->gossmap);
/* We inmediately add this payment to the payment list. */
tal_steal(pay_plugin->ctx, renepay->payment);
list_add_tail(&pay_plugin->payments, &renepay->payment->list);
tal_add_destructor(renepay->payment, destroy_payment);
/* We immediately add this payment to the payment list. */
list_add_tail(&pay_plugin->payments, &payment->list);
tal_add_destructor(payment, destroy_payment);
plugin_log(pay_plugin->plugin,LOG_DBG,"Starting renepay");
bool gossmap_changed = gossmap_refresh(pay_plugin->gossmap, NULL);
@ -1191,7 +1189,7 @@ static struct command_result *json_pay(struct command *cmd,
// TODO(eduardo): are there route hints for B12?
// Add any extra hidden channel revealed by the routehints to the uncertainty network.
if(invstr_is_b11)
uncertainty_network_add_routehints(pay_plugin->chan_extra_map,renepay);
uncertainty_network_add_routehints(pay_plugin->chan_extra_map, payment);
if(!uncertainty_network_check_invariants(pay_plugin->chan_extra_map))
plugin_log(pay_plugin->plugin,
@ -1203,9 +1201,9 @@ static struct command_result *json_pay(struct command *cmd,
struct out_req *req
= jsonrpc_request_start(cmd->plugin, cmd, "listsendpays",
payment_listsendpays_previous,
payment_listsendpays_previous, renepay);
payment_listsendpays_previous, payment);
json_add_sha256(req->js, "payment_hash", &renepay->payment->payment_hash);
json_add_sha256(req->js, "payment_hash", &payment->payment_hash);
return send_outreq(cmd->plugin, req);
}
@ -1213,12 +1211,10 @@ static void handle_sendpay_failure_renepay(
struct command *cmd,
const char *buf,
const jsmntok_t *result,
struct renepay *renepay,
struct payment *p,
struct pay_flow *flow)
{
debug_assert(renepay);
debug_assert(flow);
struct payment *p = renepay->payment;
debug_assert(p);
u64 errcode;
@ -1249,11 +1245,11 @@ static void handle_sendpay_failure_renepay(
case PAY_TRY_OTHER_ROUTE:
break;
case PAY_DESTINATION_PERM_FAIL:
renepay_fail(renepay,errcode,
payment_fail(p, errcode,
"Got a final failure from destination");
return;
default:
renepay_fail(renepay,errcode,
payment_fail(p, errcode,
"Unexpected errocode from sendpay_failure: %.*s",
json_tok_full_len(result),
json_tok_full(buf,result));
@ -1315,7 +1311,7 @@ static void handle_sendpay_failure_renepay(
{
// TODO(eduardo): I wonder which error code should I show the
// user in this case?
renepay_fail(renepay,LIGHTNINGD,
payment_fail(p,LIGHTNINGD,
"Failed to get failcode from sendpay_failure notification"
", received json: %.*s",
json_tok_full_len(result),
@ -1355,7 +1351,7 @@ static void handle_sendpay_failure_renepay(
case WIRE_EXPIRY_TOO_FAR:
debug_paynote(p, "we're removing scid %s",
type_to_string(tmpctx,struct short_channel_id,&errscid));
tal_arr_expand(&renepay->disabled, errscid);
tal_arr_expand(&p->disabled, errscid);
return;
/* These can be fixed (maybe) by applying the included channel_update */
@ -1375,7 +1371,7 @@ static void handle_sendpay_failure_renepay(
debug_paynote(p, "missing an update, so we're removing scid %s",
type_to_string(tmpctx,struct short_channel_id,&errscid));
tal_arr_expand(&renepay->disabled, errscid);
tal_arr_expand(&p->disabled, errscid);
return;
case WIRE_TEMPORARY_CHANNEL_FAILURE:
@ -1387,7 +1383,7 @@ static void handle_sendpay_failure_renepay(
case WIRE_FINAL_INCORRECT_CLTV_EXPIRY:
case WIRE_FINAL_INCORRECT_HTLC_AMOUNT:
debug_paynote(p,"final destination failure");
renepay_fail(renepay,errcode,
payment_fail(p,errcode,
"Destination said %s: %s",
onion_wire_name(onionerr),
message);
@ -1400,7 +1396,7 @@ static void handle_sendpay_failure_renepay(
{
debug_paynote(p,"unkown onion error code %u, fatal",
onionerr);
renepay_fail(renepay,errcode,
payment_fail(p,errcode,
"Destination gave unknown error code %u: %s",
onionerr,message);
return;
@ -1409,12 +1405,12 @@ static void handle_sendpay_failure_renepay(
debug_paynote(p,"unkown onion error code %u, removing scid %s",
onionerr,
type_to_string(tmpctx,struct short_channel_id,&errscid));
tal_arr_expand(&renepay->disabled, errscid);
tal_arr_expand(&p->disabled, errscid);
return;
}
unhandleable:
// TODO(eduardo): check
handle_unhandleable_error(renepay, flow, "");
handle_unhandleable_error(p, flow, "");
}
static void handle_sendpay_failure_flow(
@ -1428,7 +1424,8 @@ static void handle_sendpay_failure_flow(
debug_assert(flow);
struct payment * const p = flow->payment;
payment_fail(p);
if (p->status != PAYMENT_SUCCESS)
p->status=PAYMENT_FAIL;
u64 errcode;
if (!json_to_u64(buf, json_get_member(buf, result, "code"), &errcode))
@ -1620,8 +1617,7 @@ static struct command_result *notification_sendpay_success(
// 3. mark as success
struct payment * const p = flow->payment;
debug_assert(p);
payment_success(p);
p->status = PAYMENT_SUCCESS;
const jsmntok_t *preimagetok
= json_get_member(buf, resulttok, "payment_preimage");
@ -1633,6 +1629,8 @@ static struct command_result *notification_sendpay_success(
json_tok_full_len(params),
json_tok_full(buf,params));
/* We could have preimage from previous part */
tal_free(p->preimage);
p->preimage = tal_dup_or_null(p,struct preimage,&preimage);
// 4. update information and release pending HTLCs
@ -1706,10 +1704,7 @@ static struct command_result *notification_sendpay_failure(
handle_sendpay_failure_flow(cmd,buf,resulttok,flow);
// there is possibly a pending renepay command for this flow
struct renepay * const renepay = flow->payment->renepay;
if(renepay)
handle_sendpay_failure_renepay(cmd,buf,resulttok,renepay,flow);
handle_sendpay_failure_renepay(cmd,buf,resulttok,flow->payment,flow);
done:
if(flow) payflow_fail(flow);

View file

@ -137,11 +137,10 @@ static u64 flow_delay(const struct flow *flow)
/* This enhances f->amounts, and returns per-flow cltvs */
static u32 *shadow_additions(const tal_t *ctx,
const struct gossmap *gossmap,
struct renepay *renepay,
struct payment *p,
struct flow **flows,
bool is_entire_payment)
{
struct payment * p = renepay->payment;
u32 *final_cltvs;
/* Set these up now in case we decide to do nothing */
@ -279,12 +278,11 @@ static u64 flows_worst_delay(struct flow **flows)
}
/* FIXME: If only path has channels marked disabled, we should try... */
static bool disable_htlc_violations_oneflow(struct renepay * renepay,
static bool disable_htlc_violations_oneflow(struct payment *p,
const struct flow *flow,
const struct gossmap *gossmap,
bitmap *disabled)
{
struct payment * p = renepay->payment;
bool disabled_some = false;
for (size_t i = 0; i < tal_count(flow->path); i++) {
@ -307,7 +305,7 @@ static bool disable_htlc_violations_oneflow(struct renepay * renepay,
reason);
/* Add this for future searches for this payment. */
tal_arr_expand(&renepay->disabled, scid);
tal_arr_expand(&p->disabled, scid);
/* Add to existing bitmap */
bitmap_set_bit(disabled,
gossmap_chan_idx(gossmap, flow->path[i]));
@ -318,7 +316,7 @@ static bool disable_htlc_violations_oneflow(struct renepay * renepay,
/* If we can't use one of these flows because we hit limits, we disable that
* channel for future searches and return false */
static bool disable_htlc_violations(struct renepay *renepay,
static bool disable_htlc_violations(struct payment *payment,
struct flow **flows,
const struct gossmap *gossmap,
bitmap *disabled)
@ -327,7 +325,7 @@ static bool disable_htlc_violations(struct renepay *renepay,
/* We continue through all of them, to disable many at once. */
for (size_t i = 0; i < tal_count(flows); i++) {
disabled_some |= disable_htlc_violations_oneflow(renepay, flows[i],
disabled_some |= disable_htlc_violations_oneflow(payment, flows[i],
gossmap,
disabled);
}
@ -335,7 +333,7 @@ static bool disable_htlc_violations(struct renepay *renepay,
}
/* Get some payment flows to get this amount to destination, or NULL. */
struct pay_flow **get_payflows(struct renepay * renepay,
struct pay_flow **get_payflows(struct payment *p,
struct amount_msat amount,
struct amount_msat feebudget,
bool unlikely_ok,
@ -344,12 +342,11 @@ struct pay_flow **get_payflows(struct renepay * renepay,
{
*err_msg = tal_fmt(tmpctx,"[no error]");
struct payment * p = renepay->payment;
bitmap *disabled;
struct pay_flow **pay_flows;
const struct gossmap_node *src, *dst;
disabled = make_disabled_bitmap(tmpctx, pay_plugin->gossmap, renepay->disabled);
disabled = make_disabled_bitmap(tmpctx, pay_plugin->gossmap, p->disabled);
src = gossmap_find_node(pay_plugin->gossmap, &pay_plugin->my_id);
if (!src) {
debug_paynote(p, "We don't have any channels?");
@ -453,7 +450,7 @@ struct pay_flow **get_payflows(struct renepay * renepay,
* to do this inside minflow(), but the diagnostics here
* are far better, since we can report min/max which
* *actually* made us reconsider. */
if (disable_htlc_violations(renepay, flows, pay_plugin->gossmap,
if (disable_htlc_violations(p, flows, pay_plugin->gossmap,
disabled))
{
continue; // retry
@ -462,12 +459,12 @@ struct pay_flow **get_payflows(struct renepay * renepay,
/* This can adjust amounts and final cltv for each flow,
* to make it look like it's going elsewhere */
final_cltvs = shadow_additions(tmpctx, pay_plugin->gossmap,
renepay, flows, is_entire_payment);
p, flows, is_entire_payment);
/* OK, we are happy with these flows: convert to
* pay_flows to outlive the current gossmap. */
pay_flows = flows_to_pay_flows(renepay->payment, pay_plugin->gossmap,
pay_flows = flows_to_pay_flows(p, pay_plugin->gossmap,
flows, final_cltvs,
&renepay->next_partid);
&p->next_partid);
break;
}
@ -628,7 +625,8 @@ struct pay_flow* payflow_fail(struct pay_flow *flow)
struct payment * p = flow->payment;
debug_assert(p);
payment_fail(p);
if (p->status != PAYMENT_SUCCESS)
p->status = PAYMENT_FAIL;
amount_msat_reduce(&p->total_delivering, payflow_delivered(flow));
amount_msat_reduce(&p->total_sent, flow->amounts[0]);

View file

@ -78,7 +78,7 @@ HTABLE_DEFINE_TYPE(struct pay_flow,
payflow_map);
struct pay_flow **get_payflows(struct renepay * renepay,
struct pay_flow **get_payflows(struct payment *payment,
struct amount_msat amount,
struct amount_msat feebudget,
bool unlikely_ok,

View file

@ -3,7 +3,8 @@
#include <plugins/renepay/debug.h>
#include <plugins/renepay/payment.h>
static struct payment * payment_new(struct renepay * renepay,
struct payment *payment_new(const tal_t *ctx,
struct command *cmd,
const char *invstr TAKES,
const char *label TAKES,
const char *description TAKES,
@ -24,8 +25,8 @@ static struct payment * payment_new(struct renepay * renepay,
u64 min_prob_success_millionths,
bool use_shadow)
{
struct payment *p = tal(renepay,struct payment);
p->renepay = renepay;
struct payment *p = tal(ctx,struct payment);
p->cmd = cmd;
p->paynotes = tal_arr(p, const char *, 0);
p->total_sent = AMOUNT_MSAT(0);
@ -61,66 +62,14 @@ static struct payment * payment_new(struct renepay * renepay,
p->groupid=1;
p->result = NULL;
p->local_gossmods = gossmap_localmods_new(p);
p->disabled = tal_arr(p,struct short_channel_id,0);
p->rexmit_timer = NULL;
p->next_partid=1;
return p;
}
struct renepay *renepay_new(struct command *cmd,
const char *invstr TAKES,
const char *label TAKES,
const char *description TAKES,
const struct sha256 *local_offer_id TAKES,
const struct secret *payment_secret TAKES,
const u8 *payment_metadata TAKES,
const struct node_id *destination,
const struct sha256 *payment_hash,
struct amount_msat amount,
struct amount_msat maxfee,
unsigned int maxdelay,
u64 retryfor,
u16 final_cltv,
/* Tweakable in DEVELOPER mode */
u64 base_fee_penalty,
u64 prob_cost_factor,
u64 riskfactor_millionths,
u64 min_prob_success_millionths,
bool use_shadow)
{
struct renepay *renepay = tal(cmd,struct renepay);
renepay->cmd = cmd;
renepay->payment = payment_new(renepay,
invstr, label, description,
local_offer_id, payment_secret, payment_metadata,
destination, payment_hash,
amount, maxfee, maxdelay,
retryfor, final_cltv,
base_fee_penalty,
prob_cost_factor,
riskfactor_millionths,
min_prob_success_millionths,
use_shadow);
renepay->local_gossmods = gossmap_localmods_new(renepay);
renepay->disabled = tal_arr(renepay,struct short_channel_id,0);
renepay->rexmit_timer = NULL;
renepay->next_partid=1;
return renepay;
}
void payment_fail(struct payment * p)
{
/* If the payment already succeeded this function call must correspond
* to an old sendpay. */
if(p->status == PAYMENT_SUCCESS)return;
p->status=PAYMENT_FAIL;
}
void payment_success(struct payment * p)
{
p->status=PAYMENT_SUCCESS;
}
struct amount_msat payment_sent(const struct payment *p)
{
return p->total_sent;
@ -180,22 +129,25 @@ void payment_assert_delivering_all(const struct payment *p)
}
}
struct command_result *renepay_success(struct renepay * renepay)
struct command_result *payment_success(struct payment *p)
{
debug_info("calling %s",__PRETTY_FUNCTION__);
struct payment *p = renepay->payment;
payment_success(p);
p->status = PAYMENT_SUCCESS;
payment_assert_delivering_all(p);
/* We only finish command once: its destructor clears this. */
if (!p->cmd)
return NULL;
struct json_stream *response
= jsonrpc_stream_success(renepay->cmd);
= jsonrpc_stream_success(p->cmd);
/* Any one succeeding is success. */
json_add_preimage(response, "payment_preimage", p->preimage);
json_add_sha256(response, "payment_hash", &p->payment_hash);
json_add_timeabs(response, "created_at", p->start_time);
json_add_u32(response, "parts", renepay_parts(renepay));
json_add_u32(response, "parts", payment_parts(p));
json_add_amount_msat(response, "amount_msat",
p->amount);
json_add_amount_msat(response, "amount_sent_msat",
@ -203,51 +155,45 @@ struct command_result *renepay_success(struct renepay * renepay)
json_add_string(response, "status", "complete");
json_add_node_id(response, "destination", &p->destination);
return command_finished(renepay->cmd, response);
return command_finished(p->cmd, response);
}
struct command_result *renepay_fail(
struct renepay * renepay,
struct command_result *payment_fail(
struct payment *payment,
enum jsonrpc_errcode code,
const char *fmt, ...)
{
/* renepay_fail is called after command finished. */
if(renepay==NULL)
{
return command_still_pending(NULL);
}
payment_fail(renepay->payment);
/* We only finish command once: its destructor clears this. */
if (!payment->cmd)
return NULL;
if (payment->status != PAYMENT_SUCCESS)
payment->status = PAYMENT_FAIL;
va_list args;
va_start(args, fmt);
char *message = tal_vfmt(tmpctx,fmt,args);
va_end(args);
debug_paynote(renepay->payment,"%s",message);
debug_paynote(payment,"%s",message);
return command_fail(renepay->cmd,code,"%s",message);
return command_fail(payment->cmd,code,"%s",message);
}
u64 renepay_parts(const struct renepay *renepay)
u64 payment_parts(const struct payment *payment)
{
return renepay->next_partid-1;
return payment->next_partid-1;
}
/* Either the payment succeeded or failed, we need to cleanup/set the plugin
* into a valid state before the next payment. */
void renepay_cleanup(
struct renepay * renepay,
struct gossmap * gossmap)
void payment_cleanup(struct payment *payment)
{
debug_info("calling %s",__PRETTY_FUNCTION__);
// TODO(eduardo): it can happen that local_gossmods removed below
// contained a set of channels for which there is information in the
// uncertainty network (chan_extra_map) and that are part of some pending
// payflow (payflow_map). Handle this situation.
tal_free(renepay->local_gossmods);
renepay->rexmit_timer = tal_free(renepay->rexmit_timer);
if(renepay->payment)
renepay->payment->renepay = NULL;
payment->local_gossmods = tal_free(payment->local_gossmods);
payment->rexmit_timer = tal_free(payment->rexmit_timer);
}

View file

@ -13,7 +13,20 @@ struct payment {
/* Inside pay_plugin->payments list */
struct list_node list;
struct renepay * renepay;
/* The command if still running (needed for timer func) */
struct command *cmd;
/* Localmods to apply to gossip_map for our own use. */
struct gossmap_localmods *local_gossmods;
/* Channels we decided to disable for various reasons. */
struct short_channel_id *disabled;
/* Timers. */
struct plugin_timer *rexmit_timer;
/* Used in get_payflows to set ids to each pay_flow. */
u64 next_partid;
/* Chatty description of attempts. */
const char **paynotes;
@ -32,7 +45,6 @@ struct payment {
struct node_id destination;
struct sha256 payment_hash;
/* Limits on what routes we'll accept. */
struct amount_msat maxspend;
@ -100,30 +112,9 @@ struct payment {
struct command_result * result;
};
/* Data only kept while the payment is being processed. */
struct renepay
{
/* The command, and our owner (needed for timer func) */
struct command *cmd;
/* Payment information that will eventually outlive renepay and be
* registered. */
struct payment * payment;
/* Localmods to apply to gossip_map for our own use. */
struct gossmap_localmods *local_gossmods;
/* Channels we decided to disable for various reasons. */
struct short_channel_id *disabled;
/* Timers. */
struct plugin_timer *rexmit_timer;
/* Used in get_payflows to set ids to each pay_flow. */
u64 next_partid;
};
struct renepay *renepay_new(struct command *cmd,
struct payment *payment_new(const tal_t *ctx,
struct command *cmd,
const char *invstr TAKES,
const char *label TAKES,
const char *description TAKES,
@ -144,12 +135,6 @@ struct renepay *renepay_new(struct command *cmd,
u64 min_prob_success_millionths,
bool use_shadow);
void renepay_cleanup(
struct renepay * renepay,
struct gossmap * gossmap);
void payment_fail(struct payment * p);
void payment_success(struct payment * p);
struct amount_msat payment_sent(const struct payment *p);
struct amount_msat payment_delivered(const struct payment *p);
struct amount_msat payment_amount(const struct payment *p);
@ -159,13 +144,14 @@ void payment_note(struct payment *p, const char *fmt, ...);
void payment_assert_delivering_incomplete(const struct payment *p);
void payment_assert_delivering_all(const struct payment *p);
struct command_result *renepay_success(struct renepay *renepay);
struct command_result *payment_success(struct payment *payment);
struct command_result *renepay_fail(
struct renepay * renepay,
struct command_result *payment_fail(
struct payment *payment,
enum jsonrpc_errcode code,
const char *fmt, ...);
u64 renepay_parts(const struct renepay *renepay);
u64 payment_parts(const struct payment *payment);
void payment_cleanup(struct payment *payment);
#endif /* LIGHTNING_PLUGINS_RENEPAY_PAYMENT_H */

View file

@ -41,7 +41,7 @@ bool uncertainty_network_check_invariants(struct chan_extra_map *chan_extra_map)
static void add_hintchan(
struct chan_extra_map *chan_extra_map,
struct renepay * renepay,
struct payment *payment,
const struct node_id *src,
const struct node_id *dst,
u16 cltv_expiry_delta,
@ -63,9 +63,9 @@ static void add_hintchan(
scid,
MAX_CAP);
/* FIXME: features? */
gossmap_local_addchan(renepay->local_gossmods,
gossmap_local_addchan(payment->local_gossmods,
src, dst, &scid, NULL);
gossmap_local_updatechan(renepay->local_gossmods,
gossmap_local_updatechan(payment->local_gossmods,
&scid,
/* We assume any HTLC is allowed */
AMOUNT_MSAT(0), MAX_CAP,
@ -84,15 +84,14 @@ static void add_hintchan(
/* Add routehints provided by bolt11 */
void uncertainty_network_add_routehints(
struct chan_extra_map *chan_extra_map,
struct renepay *renepay)
struct payment *p)
{
const struct payment *const p = renepay->payment;
struct bolt11 *b11;
char *fail;
b11 =
bolt11_decode(tmpctx, p->invstr,
plugin_feature_set(renepay->cmd->plugin),
plugin_feature_set(p->cmd->plugin),
p->description, chainparams, &fail);
if (b11 == NULL)
debug_err("add_routehints: Invalid bolt11: %s", fail);
@ -104,7 +103,7 @@ void uncertainty_network_add_routehints(
for (int j = tal_count(r)-1; j >= 0; j--) {
add_hintchan(
chan_extra_map,
renepay, &r[j].pubkey, end,
p, &r[j].pubkey, end,
r[j].cltv_expiry_delta,
r[j].short_channel_id,
r[j].fee_base_msat,
@ -232,11 +231,10 @@ void uncertainty_network_channel_can_send(
bool uncertainty_network_update_from_listpeerchannels(
struct chan_extra_map * chan_extra_map,
struct node_id my_id,
struct renepay * renepay,
struct payment *p,
const char *buf,
const jsmntok_t *toks)
{
struct payment * const p = renepay->payment;
const jsmntok_t *channels, *channel;
size_t i;
@ -270,7 +268,7 @@ bool uncertainty_network_update_from_listpeerchannels(
type_to_string(tmpctx,
struct short_channel_id,
&scid));
tal_arr_expand(&renepay->disabled, scid);
tal_arr_expand(&p->disabled, scid);
continue;
}
@ -302,7 +300,7 @@ bool uncertainty_network_update_from_listpeerchannels(
/* Don't report opening/closing channels */
if (!json_tok_streq(buf, statetok, "CHANNELD_NORMAL")) {
tal_arr_expand(&renepay->disabled, scid);
tal_arr_expand(&p->disabled, scid);
continue;
}
@ -316,9 +314,9 @@ bool uncertainty_network_update_from_listpeerchannels(
scid,
capacity);
/* FIXME: features? */
gossmap_local_addchan(renepay->local_gossmods,
gossmap_local_addchan(p->local_gossmods,
&src, &dst, &scid, NULL);
gossmap_local_updatechan(renepay->local_gossmods,
gossmap_local_updatechan(p->local_gossmods,
&scid,
/* TODO(eduardo): does it

View file

@ -14,7 +14,7 @@ bool uncertainty_network_check_invariants(struct chan_extra_map *chan_extra_map)
/* Add routehints provided by bolt11 */
void uncertainty_network_add_routehints(
struct chan_extra_map *chan_extra_map,
struct renepay *renepay);
struct payment *payment);
/* Mirror the gossmap in the public uncertainty network.
* result: Every channel in gossmap must have associated data in chan_extra_map,
@ -40,7 +40,7 @@ void uncertainty_network_channel_can_send(
bool uncertainty_network_update_from_listpeerchannels(
struct chan_extra_map * chan_extra_map,
struct node_id my_id,
struct renepay * renepay,
struct payment *payment,
const char *buf,
const jsmntok_t *toks);