diff --git a/plugins/renepay/flow.c b/plugins/renepay/flow.c index 9c7731038f3c..677ea36affda 100644 --- a/plugins/renepay/flow.c +++ b/plugins/renepay/flow.c @@ -14,7 +14,8 @@ #define SUPERVERBOSE_ENABLED 1 #endif -struct amount_msat *tal_flow_amounts(const tal_t *ctx, const struct flow *flow) +struct amount_msat *tal_flow_amounts(const tal_t *ctx, const struct flow *flow, + bool compute_fees) { const size_t pathlen = tal_count(flow->path); struct amount_msat *amounts = tal_arr(ctx, struct amount_msat, pathlen); @@ -23,7 +24,8 @@ struct amount_msat *tal_flow_amounts(const tal_t *ctx, const struct flow *flow) for (int i = (int)pathlen - 2; i >= 0; i--) { const struct half_chan *h = flow_edge(flow, i + 1); amounts[i] = amounts[i + 1]; - if (!amount_msat_add_fee(&amounts[i], h->base_fee, + if (compute_fees && + !amount_msat_add_fee(&amounts[i], h->base_fee, h->proportional_fee)) goto function_fail; } @@ -39,11 +41,7 @@ const char *fmt_flows(const tal_t *ctx, const struct gossmap *gossmap, struct flow **flows) { tal_t *this_ctx = tal(ctx, tal_t); - double tot_prob = - flowset_probability(tmpctx, flows, gossmap, chan_extra_map, NULL); - assert(tot_prob >= 0); - char *buff = tal_fmt(ctx, "%zu subflows, prob %2lf\n", tal_count(flows), - tot_prob); + char *buff = tal_fmt(ctx, "%zu subflows\n", tal_count(flows)); for (size_t i = 0; i < tal_count(flows); i++) { struct amount_msat fee, delivered; tal_append_fmt(&buff, " "); @@ -233,11 +231,20 @@ struct chan_inflight_flow struct amount_msat half[2]; }; +/* @ctx: allocator + * @flows: flows for which the probability is computed + * @gossmap: gossip + * @chan_extra_map: knowledge + * @compute_fees: compute fees along the way or not + * @fail: if a failure occurs, returns a message to the caller + * */ // TODO(eduardo): here chan_extra_map should be const // TODO(eduardo): here flows should be const double flowset_probability(const tal_t *ctx, struct flow **flows, const struct gossmap *const gossmap, - struct chan_extra_map *chan_extra_map, char **fail) + struct chan_extra_map *chan_extra_map, + bool compute_fees, + char **fail) { assert(flows); assert(gossmap); @@ -251,6 +258,12 @@ double flowset_probability(const tal_t *ctx, struct flow **flows, struct chan_inflight_flow *in_flight = tal_arr(this_ctx, struct chan_inflight_flow, max_num_chans); + if (!in_flight) { + if (fail) + *fail = tal_fmt(ctx, "failed to allocate memory"); + goto function_fail; + } + for (size_t i = 0; i < max_num_chans; ++i) { in_flight[i].half[0] = in_flight[i].half[1] = AMOUNT_MSAT(0); } @@ -258,7 +271,8 @@ double flowset_probability(const tal_t *ctx, struct flow **flows, for (size_t i = 0; i < tal_count(flows); ++i) { const struct flow *f = flows[i]; const size_t pathlen = tal_count(f->path); - struct amount_msat *amounts = tal_flow_amounts(this_ctx, f); + struct amount_msat *amounts = + tal_flow_amounts(this_ctx, f, compute_fees); if (!amounts) { if (fail) @@ -284,18 +298,32 @@ double flowset_probability(const tal_t *ctx, struct flow **flows, const struct amount_msat deliver = amounts[j]; - struct amount_msat prev_flow; + struct amount_msat prev_flow, all_inflight; if (!amount_msat_add(&prev_flow, h->htlc_total, - in_flight[c_idx].half[c_dir])) { + in_flight[c_idx].half[c_dir]) || + !amount_msat_add(&all_inflight, prev_flow, + deliver)) { if (fail) - *fail = tal_fmt( - ctx, "in-flight amount_msat overflow"); + *fail = tal_fmt( + ctx, + "in-flight amount_msat overflow"); goto function_fail; } - double edge_prob = - edge_probability(h->known_min, h->known_max, - prev_flow, deliver); + if (!amount_msat_less_eq(all_inflight, h->known_max)) { + if (fail) + *fail = tal_fmt( + ctx, + "in-flight (%s) exceeds known_max " + "(%s)", + fmt_amount_msat(ctx, all_inflight), + fmt_amount_msat(ctx, h->known_max)); + goto function_fail; + } + + double edge_prob = edge_probability( + h->known_min, h->known_max, prev_flow, deliver); + if (edge_prob < 0) { if (fail) *fail = tal_fmt(ctx, @@ -406,7 +434,8 @@ bool flow_assign_delivery(struct flow *flow, const struct gossmap *gossmap, * success provided that there are no other flows in the current MPP flow set. * */ double flow_probability(struct flow *flow, const struct gossmap *gossmap, - struct chan_extra_map *chan_extra_map) + struct chan_extra_map *chan_extra_map, + bool compute_fees) { assert(flow); assert(gossmap); @@ -425,8 +454,8 @@ double flow_probability(struct flow *flow, const struct gossmap *gossmap, if (prob < 0) goto function_fail; - if (!amount_msat_add_fee(&spend, h->base_fee, - h->proportional_fee)) + if (compute_fees && !amount_msat_add_fee(&spend, h->base_fee, + h->proportional_fee)) goto function_fail; } diff --git a/plugins/renepay/flow.h b/plugins/renepay/flow.h index 63f54f29086f..959eb42f3f64 100644 --- a/plugins/renepay/flow.h +++ b/plugins/renepay/flow.h @@ -43,7 +43,8 @@ double flow_edge_cost(const struct gossmap *gossmap, /* Compute the prob. of success of a set of concurrent set of flows. */ double flowset_probability(const tal_t *ctx, struct flow **flows, const struct gossmap *const gossmap, - struct chan_extra_map *chan_extra_map, char **fail); + struct chan_extra_map *chan_extra_map, + bool compute_fees, char **fail); /* How much do we need to send to make this flow arrive. */ bool flow_spend(struct amount_msat *ret, struct flow *flow); @@ -63,7 +64,8 @@ static inline struct amount_msat flow_delivers(const struct flow *flow) return flow->amount; } -struct amount_msat *tal_flow_amounts(const tal_t *ctx, const struct flow *flow); +struct amount_msat *tal_flow_amounts(const tal_t *ctx, const struct flow *flow, + bool compute_fees); enum renepay_errorcode flow_maximum_deliverable(struct amount_msat *max_deliverable, @@ -79,7 +81,8 @@ bool flow_assign_delivery(struct flow *flow, const struct gossmap *gossmap, struct amount_msat requested_amount); double flow_probability(struct flow *flow, const struct gossmap *gossmap, - struct chan_extra_map *chan_extra_map); + struct chan_extra_map *chan_extra_map, + bool compute_fees); u64 flow_delay(const struct flow *flow); u64 flows_worst_delay(struct flow **flows); diff --git a/plugins/renepay/main.c b/plugins/renepay/main.c index f2bee7af98d1..275cc14e6912 100644 --- a/plugins/renepay/main.c +++ b/plugins/renepay/main.c @@ -24,10 +24,9 @@ // it would be nice if listsendpay would give us the route of pending // sendpays. -struct pay_plugin *pay_plugin; - static void memleak_mark(struct plugin *p, struct htable *memtable) { + struct pay_plugin *pay_plugin = get_renepay(p); memleak_scan_obj(memtable, pay_plugin); memleak_scan_htable(memtable, &pay_plugin->uncertainty->chan_extra_map->raw); @@ -38,6 +37,7 @@ static void memleak_mark(struct plugin *p, struct htable *memtable) static const char *init(struct plugin *p, const char *buf UNUSED, const jsmntok_t *config UNUSED) { + struct pay_plugin *pay_plugin = get_renepay(p); size_t num_channel_updates_rejected = 0; tal_steal(p, pay_plugin); @@ -99,6 +99,7 @@ static struct command_result *json_paystatus(struct command *cmd, const char *buf, const jsmntok_t *params) { + struct pay_plugin *pay_plugin = get_renepay(cmd->plugin); const char *invstring; struct json_stream *ret; @@ -155,6 +156,8 @@ static struct command_result * payment_start(struct payment *p) { assert(p); p->status = PAYMENT_PENDING; + struct pay_plugin *pay_plugin = get_renepay(p->plugin); + assert(pay_plugin); plugin_log(pay_plugin->plugin, LOG_DBG, "Starting renepay"); p->exec_state = 0; return payment_continue(p); @@ -163,6 +166,8 @@ static struct command_result * payment_start(struct payment *p) static struct command_result *json_pay(struct command *cmd, const char *buf, const jsmntok_t *params) { + struct pay_plugin *pay_plugin = get_renepay(cmd->plugin); + assert(pay_plugin); /* === Parse command line arguments === */ // TODO check if we leak some of these temporary variables @@ -312,6 +317,7 @@ static struct command_result *json_pay(struct command *cmd, const char *buf, { payment = payment_new( tmpctx, + cmd->plugin, &b11->payment_hash, take(invstr), take(label), @@ -419,12 +425,12 @@ int main(int argc, char *argv[]) setup_locale(); /* Most gets initialized in init(), but set debug options here. */ - pay_plugin = tal(NULL, struct pay_plugin); + struct pay_plugin *pay_plugin = tal(NULL, struct pay_plugin); pay_plugin->debug_mcf = pay_plugin->debug_payflow = false; plugin_main( argv, - init, NULL, + init, pay_plugin, PLUGIN_RESTARTABLE, /* init_rpc */ true, /* features */ NULL, diff --git a/plugins/renepay/mcf.c b/plugins/renepay/mcf.c index 5bb6387b5b33..1499e016ee74 100644 --- a/plugins/renepay/mcf.c +++ b/plugins/renepay/mcf.c @@ -470,8 +470,14 @@ static bool linearize_channel(const struct pay_parameters *params, return false; } - assert( - amount_msat_less_eq(extra_half->htlc_total, extra_half->known_max)); + /* FIXME: this assertion has been reported to be triggered in issue + * #7535. A quick and dirty solution is to comment it and work-around + * this case. But in principle if we do things the right way we should + * not have htlc_total>known_max. The problem is likely to be + * asynchronous way in which reserved htlcs are removed and known_max is + * updated. */ + // assert( + // amount_msat_less_eq(extra_half->htlc_total, extra_half->known_max)); assert( amount_msat_less_eq(extra_half->known_min, extra_half->known_max)); @@ -1443,9 +1449,8 @@ get_flow_paths(const tal_t *ctx, const struct gossmap *gossmap, excess = amount_msat(0); fp->amount = delivered; - fp->success_prob = - flow_probability(fp, gossmap, chan_extra_map) + flow_probability(fp, gossmap, chan_extra_map, false) * pow(base_probability, tal_count(fp->path)); if (fp->success_prob < 0) { if (fail) @@ -1731,12 +1736,14 @@ struct flow **minflow(const tal_t *ctx, struct gossmap *gossmap, best_prob_success = flowset_probability(this_ctx, best_flow_paths, params->gossmap, - params->chan_extra_map, &errmsg) + params->chan_extra_map, false, &errmsg) * pow(params->base_probability, flowset_size(best_flow_paths)); if (best_prob_success < 0) { if (fail) - *fail = - tal_fmt(ctx, "flowset_probability failed: %s", errmsg); + *fail = tal_fmt( + ctx, + "flowset_probability failed on MaxFlow phase: %s", + errmsg); goto function_fail; } if (!flowset_fee(&best_fee, best_flow_paths)) { @@ -1789,7 +1796,7 @@ struct flow **minflow(const tal_t *ctx, struct gossmap *gossmap, double prob_success = flowset_probability(this_ctx, flow_paths, params->gossmap, - params->chan_extra_map, &errmsg) + params->chan_extra_map, false, &errmsg) * pow(params->base_probability, flowset_size(flow_paths)); if (prob_success < 0) { // flowset_probability doesn't fail unless there is a bug. diff --git a/plugins/renepay/mods.c b/plugins/renepay/mods.c index 2053aab2750b..2e0829f7b750 100644 --- a/plugins/renepay/mods.c +++ b/plugins/renepay/mods.c @@ -29,7 +29,7 @@ struct command_result *payment_continue(struct payment *payment) void *op = payment_virtual_program[payment->exec_state++]; if (op == OP_NULL) { - plugin_err(pay_plugin->plugin, + plugin_err(payment->plugin, "payment_continue reached the end of the virtual " "machine execution."); } else if (op == OP_CALL) { @@ -38,11 +38,11 @@ struct command_result *payment_continue(struct payment *payment) payment_virtual_program[payment->exec_state++]; if (mod == NULL) - plugin_err(pay_plugin->plugin, + plugin_err(payment->plugin, "payment_continue expected payment_modifier " "but NULL found"); - plugin_log(pay_plugin->plugin, LOG_DBG, "Calling modifier %s", + plugin_log(payment->plugin, LOG_DBG, "Calling modifier %s", mod->name); return mod->step_cb(payment); } else if (op == OP_IF) { @@ -51,11 +51,11 @@ struct command_result *payment_continue(struct payment *payment) payment_virtual_program[payment->exec_state++]; if (cond == NULL) - plugin_err(pay_plugin->plugin, + plugin_err(payment->plugin, "payment_continue expected pointer to " "condition but NULL found"); - plugin_log(pay_plugin->plugin, LOG_DBG, + plugin_log(payment->plugin, LOG_DBG, "Calling payment condition %s", cond->name); const u64 position_iftrue = @@ -66,7 +66,7 @@ struct command_result *payment_continue(struct payment *payment) return payment_continue(payment); } - plugin_err(pay_plugin->plugin, "payment_continue op code not defined"); + plugin_err(payment->plugin, "payment_continue op code not defined"); return NULL; } @@ -104,10 +104,12 @@ struct success_data { }; /* Extracts success data from listsendpays. */ -static bool success_data_from_listsendpays(const char *buf, +static bool success_data_from_listsendpays(struct command *cmd, const char *buf, const jsmntok_t *arr, struct success_data *success) { + struct pay_plugin *pay_plugin = get_renepay(cmd->plugin); + assert(pay_plugin); assert(success); size_t i; @@ -193,7 +195,7 @@ static struct command_result *previoussuccess_done(struct command *cmd, } struct success_data success; - if (!success_data_from_listsendpays(buf, arr, &success)) { + if (!success_data_from_listsendpays(cmd, buf, arr, &success)) { /* There are no success sendpays. */ return payment_continue(payment); } @@ -256,6 +258,8 @@ static struct command_result *selfpay_success(struct command *cmd, const jsmntok_t *tok, struct route *route) { + struct pay_plugin *pay_plugin = get_renepay(cmd->plugin); + assert(pay_plugin); tal_steal(tmpctx, route); // discard this route when tmpctx clears struct payment *payment = payment_map_get(pay_plugin->payment_map, route->key.payment_hash); @@ -279,6 +283,8 @@ static struct command_result *selfpay_failure(struct command *cmd, const jsmntok_t *tok, struct route *route) { + struct pay_plugin *pay_plugin = get_renepay(cmd->plugin); + assert(pay_plugin); tal_steal(tmpctx, route); // discard this route when tmpctx clears struct payment *payment = payment_map_get(pay_plugin->payment_map, route->key.payment_hash); @@ -294,6 +300,8 @@ static struct command_result *selfpay_failure(struct command *cmd, static struct command_result *selfpay_cb(struct payment *payment) { + struct pay_plugin *pay_plugin = get_renepay(payment->plugin); + assert(pay_plugin); if (!node_id_eq(&pay_plugin->my_id, &payment->payment_info.destination)) { return payment_continue(payment); @@ -327,12 +335,12 @@ REGISTER_PAYMENT_MODIFIER(selfpay, selfpay_cb); * Calls listpeerchannels to get and updated state of the local channels. */ -static void -uncertainty_update_from_listpeerchannels(struct uncertainty *uncertainty, - const struct short_channel_id_dir *scidd, - struct amount_msat max, bool enabled, - const char *buf, const jsmntok_t *chantok) +static void uncertainty_update_from_listpeerchannels( + struct pay_plugin *pay_plugin, const struct short_channel_id_dir *scidd, + struct amount_msat max, bool enabled, const char *buf, + const jsmntok_t *chantok) { + assert(pay_plugin); if (!enabled) return; @@ -384,6 +392,8 @@ static void gossmod_cb(struct gossmap_localmods *mods, const jsmntok_t *chantok, struct payment *payment) { + struct pay_plugin *pay_plugin = get_renepay(payment->plugin); + assert(pay_plugin); struct amount_msat min, max; if (scidd->dir == node_id_idx(self, peer)) { @@ -416,8 +426,8 @@ static void gossmod_cb(struct gossmap_localmods *mods, * channel as well we would have conflicting information because our * knowledge model does not take into account channel reserves. */ if (scidd->dir == node_id_idx(self, peer)) - uncertainty_update_from_listpeerchannels( - pay_plugin->uncertainty, scidd, max, enabled, buf, chantok); + uncertainty_update_from_listpeerchannels(pay_plugin, scidd, max, + enabled, buf, chantok); } static struct command_result *getmychannels_done(struct command *cmd, @@ -425,6 +435,8 @@ static struct command_result *getmychannels_done(struct command *cmd, const jsmntok_t *result, struct payment *payment) { + struct pay_plugin *pay_plugin = get_renepay(cmd->plugin); + assert(pay_plugin); // FIXME: should local gossmods be global (ie. member of pay_plugin) or // local (ie. member of payment)? payment->local_gossmods = gossmods_from_listpeerchannels( @@ -436,6 +448,8 @@ static struct command_result *getmychannels_done(struct command *cmd, static struct command_result *getmychannels_cb(struct payment *payment) { + struct pay_plugin *pay_plugin = get_renepay(payment->plugin); + assert(pay_plugin); struct command *cmd = payment_command(payment); if (!cmd) plugin_err(pay_plugin->plugin, @@ -457,9 +471,11 @@ REGISTER_PAYMENT_MODIFIER(getmychannels, getmychannels_cb); static struct command_result *refreshgossmap_cb(struct payment *payment) { - assert(pay_plugin->gossmap); // gossmap must be already initialized assert(payment); assert(payment->local_gossmods); + struct pay_plugin *pay_plugin = get_renepay(payment->plugin); + assert(pay_plugin); + assert(pay_plugin->gossmap); // gossmap must be already initialized size_t num_channel_updates_rejected = 0; bool gossmap_changed = @@ -504,6 +520,8 @@ static void add_hintchan(struct payment *payment, const struct node_id *src, { assert(payment); assert(payment->local_gossmods); + struct pay_plugin *pay_plugin = get_renepay(payment->plugin); + assert(pay_plugin); int dir = node_id_idx(src, dst); @@ -560,7 +578,7 @@ static void add_hintchan(struct payment *payment, const struct node_id *src, errmsg); } -static struct command_result *routehints_done(struct command *cmd UNUSED, +static struct command_result *routehints_done(struct command *cmd, const char *buf UNUSED, const jsmntok_t *result UNUSED, struct payment *payment) @@ -568,6 +586,8 @@ static struct command_result *routehints_done(struct command *cmd UNUSED, // FIXME are there route hints for B12? assert(payment); assert(payment->local_gossmods); + struct pay_plugin *pay_plugin = get_renepay(cmd->plugin); + assert(pay_plugin); const struct node_id *destination = &payment->payment_info.destination; const struct route_info **routehints = payment->payment_info.routehints; @@ -623,6 +643,9 @@ REGISTER_PAYMENT_MODIFIER(routehints, routehints_cb); static struct command_result *compute_routes_cb(struct payment *payment) { + assert(payment); + struct pay_plugin *pay_plugin = get_renepay(payment->plugin); + assert(pay_plugin); assert(payment->status == PAYMENT_PENDING); struct routetracker *routetracker = payment->routetracker; assert(routetracker); @@ -654,7 +677,8 @@ static struct command_result *compute_routes_cb(struct payment *payment) /* How much are we still trying to send? */ if (!amount_msat_sub(&remaining, payment->payment_info.amount, - payment->total_delivering)) { + payment->total_delivering) || + amount_msat_zero(remaining)) { plugin_log(pay_plugin->plugin, LOG_UNUSUAL, "%s: Payment is pending with full amount already " "committed. We skip the computation of new routes.", @@ -718,6 +742,8 @@ REGISTER_PAYMENT_MODIFIER(compute_routes, compute_routes_cb); static struct command_result *send_routes_cb(struct payment *payment) { assert(payment); + struct pay_plugin *pay_plugin = get_renepay(payment->plugin); + assert(pay_plugin); struct routetracker *routetracker = payment->routetracker; assert(routetracker); if (!routetracker->computed_routes || @@ -759,7 +785,7 @@ static void sleep_done(struct payment *payment) { payment->waitresult_timer = NULL; // TODO: is this compulsory? - timer_complete(pay_plugin->plugin); + timer_complete(payment->plugin); payment_continue(payment); } @@ -767,7 +793,7 @@ static struct command_result *sleep_cb(struct payment *payment) { assert(payment->waitresult_timer == NULL); payment->waitresult_timer = plugin_timer( - pay_plugin->plugin, time_from_msec(COLLECTOR_TIME_WINDOW_MSEC), sleep_done, payment); + payment->plugin, time_from_msec(COLLECTOR_TIME_WINDOW_MSEC), sleep_done, payment); struct command *cmd = payment_command(payment); assert(cmd); return command_still_pending(cmd); @@ -802,7 +828,7 @@ static struct command_result *collect_results_cb(struct payment *payment) if (!amount_msat_greater_eq(payment->total_delivering, payment->payment_info.amount)) { plugin_log( - pay_plugin->plugin, LOG_UNUSUAL, + payment->plugin, LOG_UNUSUAL, "%s: received a success sendpay for this " "payment but the total delivering amount %s " "is less than the payment amount %s.", @@ -897,6 +923,8 @@ static struct command_result *pendingsendpays_done(struct command *cmd, const jsmntok_t *result, struct payment *payment) { + struct pay_plugin *pay_plugin = get_renepay(cmd->plugin); + assert(pay_plugin); size_t i; const char *err; const jsmntok_t *t, *arr; @@ -918,7 +946,7 @@ static struct command_result *pendingsendpays_done(struct command *cmd, } struct success_data success; - if (success_data_from_listsendpays(buf, arr, &success)) { + if (success_data_from_listsendpays(cmd, buf, arr, &success)) { /* Have success data, hence the payment is complete, we stop. */ payment->payment_info.start_time.ts.tv_sec = success.created_at; payment->payment_info.start_time.ts.tv_nsec = 0; @@ -1067,6 +1095,8 @@ REGISTER_PAYMENT_MODIFIER(pendingsendpays, pendingsendpays_cb); static struct command_result *knowledgerelax_cb(struct payment *payment) { + struct pay_plugin *pay_plugin = get_renepay(payment->plugin); + assert(pay_plugin); const u64 now_sec = time_now().ts.tv_sec; enum renepay_errorcode err = uncertainty_relax( pay_plugin->uncertainty, now_sec - pay_plugin->last_time); @@ -1101,6 +1131,8 @@ REGISTER_PAYMENT_MODIFIER(knowledgerelax, knowledgerelax_cb); static struct command_result *channelfilter_cb(struct payment *payment) { assert(payment); + struct pay_plugin *pay_plugin = get_renepay(payment->plugin); + assert(pay_plugin); assert(pay_plugin->gossmap); const double HTLC_MAX_FRACTION = 0.01; // 1% const u64 HTLC_MAX_STOP_MSAT = 1000000000; // 1M sats diff --git a/plugins/renepay/payment.c b/plugins/renepay/payment.c index 58c18f670a2e..d1bf453ab904 100644 --- a/plugins/renepay/payment.c +++ b/plugins/renepay/payment.c @@ -14,6 +14,7 @@ static struct command_result *payment_finish(struct payment *p); struct payment *payment_new( const tal_t *ctx, + struct plugin *plugin, const struct sha256 *payment_hash, const char *invstr TAKES, const char *label TAKES, @@ -38,6 +39,7 @@ struct payment *payment_new( { struct payment *p = tal(ctx, struct payment); struct payment_info *pinfo = &p->payment_info; + p->plugin = plugin; /* === Unique properties === */ assert(payment_hash); @@ -246,7 +248,7 @@ struct amount_msat payment_fees(const struct payment *p) if (!amount_msat_sub(&fees, sent, delivered)) plugin_err( - pay_plugin->plugin, + p->plugin, "Strange, sent amount (%s) is less than delivered (%s), " "aborting.", fmt_amount_msat(tmpctx, sent), @@ -348,7 +350,7 @@ void payment_note(struct payment *p, enum log_level lvl, const char *fmt, ...) tal_arr_expand(&p->paynotes, str); /* Log at debug, unless it's weird... */ - plugin_log(pay_plugin->plugin, lvl < LOG_UNUSUAL ? LOG_DBG : lvl, "%s", + plugin_log(p->plugin, lvl < LOG_UNUSUAL ? LOG_DBG : lvl, "%s", str); for (size_t i = 0; i < tal_count(p->cmd_array); i++) { diff --git a/plugins/renepay/payment.h b/plugins/renepay/payment.h index 37e104127279..a97f094f4e20 100644 --- a/plugins/renepay/payment.h +++ b/plugins/renepay/payment.h @@ -69,6 +69,9 @@ struct payment { struct plugin_timer *waitresult_timer; struct routetracker *routetracker; + + /* able to write logs */ + struct plugin *plugin; }; static inline const struct sha256 payment_hash(const struct payment *p) @@ -99,6 +102,7 @@ HTABLE_DEFINE_TYPE(struct payment, payment_hash, payment_hash64, struct payment *payment_new( const tal_t *ctx, + struct plugin *plugin, const struct sha256 *payment_hash, const char *invstr TAKES, const char *label TAKES, diff --git a/plugins/renepay/payplugin.h b/plugins/renepay/payplugin.h index a0da496f048d..037489a219bc 100644 --- a/plugins/renepay/payplugin.h +++ b/plugins/renepay/payplugin.h @@ -87,7 +87,11 @@ struct pay_plugin { u64 last_time; }; -/* Set in init */ -extern struct pay_plugin *pay_plugin; +static inline struct pay_plugin *get_renepay(struct plugin *plugin) +{ + if (plugin) + return plugin_get_data(plugin, struct pay_plugin); + return NULL; +} #endif /* LIGHTNING_PLUGINS_RENEPAY_PAYPLUGIN_H */ diff --git a/plugins/renepay/routebuilder.c b/plugins/renepay/routebuilder.c index 5b0f69c81f68..1b45308962f5 100644 --- a/plugins/renepay/routebuilder.c +++ b/plugins/renepay/routebuilder.c @@ -166,6 +166,11 @@ struct route **get_routes(const tal_t *ctx, "Failed to build disabled_bitmap."); goto function_fail; } + if (amount_msat_zero(amount_to_deliver)) { + tal_report_error(ctx, ecode, fail, PLUGIN_ERROR, + "amount to deliver is zero"); + goto function_fail; + } /* Also disable every channel that we don't have in the chan_extra_map. * We might have channels in the gossmap that are not usable for @@ -280,7 +285,7 @@ struct route **get_routes(const tal_t *ctx, const double prob = flow_probability( flows[i], gossmap, - uncertainty_get_chan_extra_map(uncertainty)); + uncertainty_get_chan_extra_map(uncertainty), true); if (prob < 0) { // should not happen tal_report_error(ctx, ecode, fail, PLUGIN_ERROR, diff --git a/plugins/renepay/routefail.c b/plugins/renepay/routefail.c index 175b7d5b03d4..b7c12b8ac6b1 100644 --- a/plugins/renepay/routefail.c +++ b/plugins/renepay/routefail.c @@ -25,6 +25,8 @@ static struct command_result *handle_failure(struct routefail *r); struct command_result *routefail_start(const tal_t *ctx, struct route *route, struct command *cmd) { + struct pay_plugin *pay_plugin = get_renepay(cmd->plugin); + assert(pay_plugin); assert(route); struct routefail *r = tal(ctx, struct routefail); struct payment *payment = diff --git a/plugins/renepay/routetracker.c b/plugins/renepay/routetracker.c index f08f8becbd78..b0c384e9b1ec 100644 --- a/plugins/renepay/routetracker.c +++ b/plugins/renepay/routetracker.c @@ -6,7 +6,8 @@ #include #include -static struct payment *route_get_payment_verify(struct route *route) +static struct payment *route_get_payment_verify(struct pay_plugin *pay_plugin, + struct route *route) { struct payment *payment = payment_map_get(pay_plugin->payment_map, route->key.payment_hash); @@ -21,7 +22,7 @@ static struct payment *route_get_payment_verify(struct route *route) struct routetracker *new_routetracker(const tal_t *ctx, struct payment *payment) { struct routetracker *rt = tal(ctx, struct routetracker); - + rt->plugin = payment->plugin; rt->computed_routes = tal_arr(rt, struct route *, 0); rt->sent_routes = tal(rt, struct route_map); rt->finalized_routes = tal_arr(rt, struct route *, 0); @@ -48,6 +49,8 @@ void routetracker_cleanup(struct routetracker *routetracker) static void routetracker_add_to_final(struct routetracker *routetracker, struct route *route) { + struct pay_plugin *pay_plugin = get_renepay(routetracker->plugin); + assert(pay_plugin); tal_arr_expand(&routetracker->finalized_routes, route); tal_steal(routetracker->finalized_routes, route); @@ -90,6 +93,8 @@ static void routetracker_add_to_final(struct routetracker *routetracker, static void route_success_register(struct routetracker *routetracker, struct route *route) { + struct pay_plugin *pay_plugin = get_renepay(routetracker->plugin); + assert(pay_plugin); if(route->hops){ uncertainty_route_success(pay_plugin->uncertainty, route); } @@ -98,6 +103,8 @@ static void route_success_register(struct routetracker *routetracker, void route_failure_register(struct routetracker *routetracker, struct route *route) { + struct pay_plugin *pay_plugin = get_renepay(routetracker->plugin); + assert(pay_plugin); struct payment_result *result = route->result; assert(result); @@ -138,9 +145,9 @@ void route_failure_register(struct routetracker *routetracker, routetracker_add_to_final(routetracker, route); } -static void remove_route(struct route *route, struct route_map *map) +static void remove_route(struct route *route, struct pay_plugin *pay_plugin) { - route_map_del(map, route); + route_map_del(pay_plugin->pending_routes, route); uncertainty_remove_htlcs(pay_plugin->uncertainty, route); } @@ -152,9 +159,11 @@ static void remove_route(struct route *route, struct route_map *map) static void route_pending_register(struct routetracker *routetracker, struct route *route) { + struct pay_plugin *pay_plugin = get_renepay(routetracker->plugin); + assert(pay_plugin); assert(route); assert(routetracker); - struct payment *payment = route_get_payment_verify(route); + struct payment *payment = route_get_payment_verify(pay_plugin, route); assert(payment); assert(payment->groupid == route->key.groupid); @@ -176,8 +185,7 @@ static void route_pending_register(struct routetracker *routetracker, if (!tal_steal(pay_plugin->pending_routes, route) || !route_map_add(pay_plugin->pending_routes, route) || - !tal_add_destructor2(route, remove_route, - pay_plugin->pending_routes)) + !tal_add_destructor2(route, remove_route, pay_plugin)) plugin_err(pay_plugin->plugin, "%s: failed to register route.", __func__); @@ -198,8 +206,10 @@ static struct command_result *sendpay_done(struct command *cmd, const jsmntok_t *result UNUSED, struct route *route) { + struct pay_plugin *pay_plugin = get_renepay(cmd->plugin); + assert(pay_plugin); assert(route); - struct payment *payment = route_get_payment_verify(route); + struct payment *payment = route_get_payment_verify(pay_plugin, route); route_pending_register(payment->routetracker, route); return command_still_pending(cmd); } @@ -213,8 +223,10 @@ static struct command_result *sendpay_failed(struct command *cmd, const jsmntok_t *tok, struct route *route) { + struct pay_plugin *pay_plugin = get_renepay(cmd->plugin); + assert(pay_plugin); assert(route); - struct payment *payment = route_get_payment_verify(route); + struct payment *payment = route_get_payment_verify(pay_plugin, route); struct routetracker *routetracker = payment->routetracker; assert(routetracker); @@ -263,6 +275,8 @@ void payment_collect_results(struct payment *payment, const char **final_msg) { assert(payment); + struct pay_plugin *pay_plugin = get_renepay(payment->plugin); + assert(pay_plugin); struct routetracker *routetracker = payment->routetracker; assert(routetracker); const size_t ncompleted = tal_count(routetracker->finalized_routes); @@ -328,6 +342,8 @@ struct command_result *route_sendpay_request(struct command *cmd, struct route *route TAKES, struct payment *payment) { + struct pay_plugin *pay_plugin = get_renepay(cmd->plugin); + assert(pay_plugin); struct out_req *req = jsonrpc_request_start(pay_plugin->plugin, cmd, "sendpay", sendpay_done, sendpay_failed, route); @@ -344,6 +360,8 @@ struct command_result *notification_sendpay_failure(struct command *cmd, const char *buf, const jsmntok_t *params) { + struct pay_plugin *pay_plugin = get_renepay(cmd->plugin); + assert(pay_plugin); plugin_log(pay_plugin->plugin, LOG_DBG, "sendpay_failure notification: %.*s", json_tok_full_len(params), json_tok_full(buf, params)); @@ -411,6 +429,8 @@ struct command_result *notification_sendpay_success(struct command *cmd, const char *buf, const jsmntok_t *params) { + struct pay_plugin *pay_plugin = get_renepay(cmd->plugin); + assert(pay_plugin); plugin_log(pay_plugin->plugin, LOG_DBG, "sendpay_success notification: %.*s", json_tok_full_len(params), json_tok_full(buf, params)); diff --git a/plugins/renepay/routetracker.h b/plugins/renepay/routetracker.h index 2e4c440a2339..b9c1e961549c 100644 --- a/plugins/renepay/routetracker.h +++ b/plugins/renepay/routetracker.h @@ -7,6 +7,9 @@ #include struct routetracker{ + /* able to write logs */ + struct plugin *plugin; + /* Routes that we compute and are kept here before sending them. */ struct route **computed_routes; diff --git a/plugins/renepay/test/common.h b/plugins/renepay/test/common.h index 6fd6e991fbcc..3368bdb49e54 100644 --- a/plugins/renepay/test/common.h +++ b/plugins/renepay/test/common.h @@ -18,7 +18,8 @@ static const char *print_routes(const tal_t *ctx, delivered = route_delivers(routes[i]); fee = route_fees(routes[i]); tal_append_fmt(&buff, " %s", fmt_route_path(this_ctx, routes[i])); - tal_append_fmt(&buff, " %s delivered with fee %s\n", + tal_append_fmt(&buff, " prob %.2f, %s delivered with fee %s\n", + routes[i]->success_prob, fmt_amount_msat(this_ctx, delivered), fmt_amount_msat(this_ctx, fee)); } diff --git a/plugins/renepay/test/run-bottleneck.c b/plugins/renepay/test/run-bottleneck.c index b2460861ac12..510ddebde5e7 100644 --- a/plugins/renepay/test/run-bottleneck.c +++ b/plugins/renepay/test/run-bottleneck.c @@ -34,7 +34,7 @@ static const char *print_flows(const tal_t *ctx, const char *desc, { tal_t *this_ctx = tal(ctx, tal_t); double tot_prob = - flowset_probability(tmpctx, flows, gossmap, chan_extra_map, NULL); + flowset_probability(tmpctx, flows, gossmap, chan_extra_map, false, NULL); assert(tot_prob >= 0); char *buff = tal_fmt(ctx, "%s: %zu subflows, prob %2lf\n", desc, tal_count(flows), tot_prob); @@ -190,7 +190,8 @@ int main(int argc, char *argv[]) assert(skipped_count==0); bitmap *disabled = tal_arrz( - tmpctx, bitmap, BITMAP_NWORDS(gossmap_max_chan_idx(gossmap))); + tmpctx, bitmap, 2 * BITMAP_NWORDS(gossmap_max_chan_idx(gossmap))); + assert(disabled); char *errmsg; struct flow **flows; @@ -208,11 +209,11 @@ int main(int argc, char *argv[]) /* prob cost factor = */ 10, &errmsg); if (!flows) { - printf("Minflow has failed with: %s", errmsg); - // assert(0 && "minflow failed"); - } + printf("Minflow has failed with: %s\n", errmsg); + assert(flows); + } - if(flows) + if(flows) printf("%s\n", print_flows(tmpctx, "Simple minflow", gossmap, uncertainty->chan_extra_map, flows)); @@ -274,10 +275,9 @@ int main(int argc, char *argv[]) &errcode, &err_msg); - assert(routes); - if (!routes) { - printf("get_route failed with error %d: %s", errcode, err_msg); + printf("get_route failed with error %d: %s\n", errcode, err_msg); + assert(routes); } if(routes) printf("get_routes: %s\n", print_routes(tmpctx, routes)); diff --git a/plugins/renepay/test/run-mcf-diamond.c b/plugins/renepay/test/run-mcf-diamond.c index 5139bb3c80de..57e90db1dca2 100644 --- a/plugins/renepay/test/run-mcf-diamond.c +++ b/plugins/renepay/test/run-mcf-diamond.c @@ -69,7 +69,7 @@ static const char* print_flows( { tal_t *this_ctx = tal(ctx,tal_t); double tot_prob = - flowset_probability(tmpctx, flows, gossmap, chan_extra_map, NULL); + flowset_probability(tmpctx, flows, gossmap, chan_extra_map, false, NULL); assert(tot_prob>=0); char *buff = tal_fmt(ctx,"%s: %zu subflows, prob %2lf\n", desc, tal_count(flows),tot_prob); for (size_t i = 0; i < tal_count(flows); i++) { diff --git a/plugins/renepay/test/run-mcf.c b/plugins/renepay/test/run-mcf.c index 9bacb9e24dff..79c291fe92c4 100644 --- a/plugins/renepay/test/run-mcf.c +++ b/plugins/renepay/test/run-mcf.c @@ -423,7 +423,7 @@ int main(int argc, char *argv[]) printf("Checking results.\n"); /* Should go 1->2->3 */ - amounts = tal_flow_amounts(tmpctx, flows[0]); + amounts = tal_flow_amounts(tmpctx, flows[0], true); assert(amounts); assert(tal_count(flows) == 1); assert(tal_count(flows[0]->path) == 2); @@ -440,7 +440,7 @@ int main(int argc, char *argv[]) /* Each one has probability ~ 0.5 */ assert(flows[0]->success_prob > 0.249); - assert(flows[0]->success_prob <= 0.250); + assert(flows[0]->success_prob <= 0.251); /* Should have filled in some extra data! */ diff --git a/plugins/renepay/test/run-testflow.c b/plugins/renepay/test/run-testflow.c index d746a62e3803..5d907bae1547 100644 --- a/plugins/renepay/test/run-testflow.c +++ b/plugins/renepay/test/run-testflow.c @@ -695,7 +695,7 @@ static void test_flow_to_route(void) assert(route); assert(amount_msat_eq(route->hops[0].amount, deliver)); - assert(fabs(flow_probability(F, gossmap, chan_extra_map) - 0.5)4->5 F = tal(this_ctx, struct flow); @@ -711,7 +711,7 @@ static void test_flow_to_route(void) assert(route); assert(amount_msat_eq(route->hops[0].amount, amount_msat(250050016))); - assert(fabs(flow_probability(F, gossmap, chan_extra_map) - 1.)3->4->5 F = tal(this_ctx, struct flow); @@ -729,7 +729,7 @@ static void test_flow_to_route(void) assert(route); assert(amount_msat_eq(route->hops[0].amount, amount_msat(250087534))); - assert(fabs(flow_probability(F, gossmap, chan_extra_map) - 1. + 250.087534/2000)2->3->4->5 F = tal(this_ctx, struct flow); @@ -749,7 +749,7 @@ static void test_flow_to_route(void) assert(route); assert(amount_msat_eq(route->hops[0].amount, amount_msat(250112544))); - assert(fabs(flow_probability(F, gossmap, chan_extra_map) - 0.43728117)