Skip to content

Commit c30ca3c

Browse files
committed
renepay: now calls getroutes
Changelog-EXPERIMENTAL: Renepay uses getroutes rpc to obtain payment routes. Signed-off-by: Lagrang3 <[email protected]>
1 parent 5ec5580 commit c30ca3c

File tree

1 file changed

+110
-44
lines changed

1 file changed

+110
-44
lines changed

plugins/renepay/mods.c

Lines changed: 110 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -632,9 +632,55 @@ REGISTER_PAYMENT_MODIFIER(routehints, routehints_cb);
632632
* Compute the payment routes.
633633
*/
634634

635-
static struct command_result *compute_routes_cb(struct payment *payment)
635+
static bool json_to_myroute(const char *buf, const jsmntok_t *tok,
636+
struct route *route)
637+
{
638+
u64 probability_ppm;
639+
const char *err =
640+
json_scan(tmpctx, buf, tok, "{probability_ppm:%,amount_msat:%}",
641+
JSON_SCAN(json_to_u64, &probability_ppm),
642+
JSON_SCAN(json_to_msat, &route->amount));
643+
if (err)
644+
return false;
645+
route->success_prob = probability_ppm * 1e-6;
646+
const jsmntok_t *path_tok = json_get_member(buf, tok, "path");
647+
if (!path_tok || path_tok->type != JSMN_ARRAY)
648+
return false;
649+
650+
route->hops = tal_arr(route, struct route_hop, path_tok->size);
651+
if (!route->hops)
652+
return false;
653+
654+
size_t i;
655+
const jsmntok_t *hop_tok;
656+
json_for_each_arr(i, hop_tok, path_tok)
657+
{
658+
struct route_hop *hop = &route->hops[i];
659+
err = json_scan(tmpctx, buf, hop_tok,
660+
"{short_channel_id:%,direction:%,next_node_id:%"
661+
",amount_msat:%,delay:%}",
662+
JSON_SCAN(json_to_short_channel_id, &hop->scid),
663+
JSON_SCAN(json_to_int, &hop->direction),
664+
JSON_SCAN(json_to_node_id, &hop->node_id),
665+
JSON_SCAN(json_to_msat, &hop->amount),
666+
JSON_SCAN(json_to_u32, &hop->delay));
667+
if (err) {
668+
route->hops = tal_free(route->hops);
669+
return false;
670+
}
671+
}
672+
route->amount_sent = route->hops[0].amount;
673+
/* FIXME: it seems that the route we get in response claims to deliver
674+
* an amount which is different to the amount in the last hop. */
675+
route->amount = route->hops[path_tok->size-1].amount;
676+
return true;
677+
}
678+
679+
static struct command_result *getroutes_done(struct command *cmd UNUSED,
680+
const char *buf,
681+
const jsmntok_t *result,
682+
struct payment *payment)
636683
{
637-
assert(payment->status == PAYMENT_PENDING);
638684
struct routetracker *routetracker = payment->routetracker;
639685
assert(routetracker);
640686

@@ -643,7 +689,49 @@ static struct command_result *compute_routes_cb(struct payment *payment)
643689
plugin_err(pay_plugin->plugin,
644690
"%s: no previously computed routes expected.",
645691
__func__);
692+
routetracker->computed_routes = tal_free(routetracker->computed_routes);
693+
694+
const jsmntok_t *routes_tok = json_get_member(buf, result, "routes");
695+
assert(routes_tok && routes_tok->type == JSMN_ARRAY);
696+
697+
routetracker->computed_routes =
698+
tal_arr(routetracker, struct route *, 0);
699+
700+
size_t i;
701+
const jsmntok_t *r;
702+
json_for_each_arr(i, r, routes_tok)
703+
{
704+
struct route *route = new_route(
705+
routetracker->computed_routes, payment->groupid,
706+
payment->next_partid++, payment->payment_info.payment_hash,
707+
AMOUNT_MSAT(0), AMOUNT_MSAT(0));
708+
assert(route);
709+
tal_arr_expand(&routetracker->computed_routes, route);
710+
bool success = json_to_myroute(buf, r, route);
711+
if (!success)
712+
plugin_err(pay_plugin->plugin,
713+
"%s: failed to parse route from json: %.*s",
714+
__func__, json_tok_full_len(r),
715+
json_tok_full(buf, r));
716+
const size_t pathlen = tal_count(route->hops);
717+
if (!amount_msat_eq(route->amount,
718+
route->hops[pathlen - 1].amount))
719+
plugin_log(pay_plugin->plugin, LOG_UNUSUAL,
720+
"%s: route partid=%" PRIu64
721+
" delivers %s which is different from what "
722+
"it claims to "
723+
"deliver %s",
724+
__func__, route->key.partid,
725+
fmt_amount_msat(
726+
tmpctx, route->hops[pathlen - 1].amount),
727+
fmt_amount_msat(tmpctx, route->amount));
728+
}
729+
return payment_continue(payment);
730+
}
646731

732+
static struct command_result *compute_routes_cb(struct payment *payment)
733+
{
734+
assert(payment->status == PAYMENT_PENDING);
647735
struct amount_msat feebudget, fees_spent, remaining;
648736

649737
/* Total feebudget */
@@ -674,48 +762,26 @@ static struct command_result *compute_routes_cb(struct payment *payment)
674762
return payment_continue(payment);
675763
}
676764

677-
enum jsonrpc_errcode errcode;
678-
const char *err_msg = NULL;
679-
680-
gossmap_apply_localmods(pay_plugin->gossmap, payment->local_gossmods);
681-
682-
/* get_routes returns the answer, we assign it to the computed_routes,
683-
* that's why we need to tal_free the older array. Maybe it would be
684-
* better to pass computed_routes as a reference? */
685-
routetracker->computed_routes = tal_free(routetracker->computed_routes);
686-
687-
// TODO: add an algorithm selector here
688-
/* We let this return an unlikely path, as it's better to try once than
689-
* simply refuse. Plus, models are not truth! */
690-
routetracker->computed_routes = get_routes(
691-
routetracker,
692-
&payment->payment_info,
693-
&pay_plugin->my_id,
694-
&payment->payment_info.destination,
695-
pay_plugin->gossmap,
696-
pay_plugin->uncertainty,
697-
payment->disabledmap,
698-
remaining,
699-
feebudget,
700-
&payment->next_partid,
701-
payment->groupid,
702-
&errcode,
703-
&err_msg);
704-
/* Otherwise the error message remains a child of the routetracker. */
705-
err_msg = tal_steal(tmpctx, err_msg);
706-
707-
gossmap_remove_localmods(pay_plugin->gossmap, payment->local_gossmods);
708-
709-
/* Couldn't feasible route, we stop. */
710-
if (!routetracker->computed_routes ||
711-
tal_count(routetracker->computed_routes) == 0) {
712-
if (err_msg == NULL)
713-
err_msg = tal_fmt(
714-
tmpctx, "get_routes returned NULL error message");
715-
return payment_fail(payment, errcode, "%s", err_msg);
716-
}
717-
718-
return payment_continue(payment);
765+
struct command *cmd = payment_command(payment);
766+
assert(cmd);
767+
struct out_req *req =
768+
jsonrpc_request_start(cmd->plugin, cmd, "getroutes", getroutes_done,
769+
payment_rpc_failure, payment);
770+
// FIXME: when multi-destination is needed to fully support blinded path
771+
// FIXME: we could have more than one algorithm to compute routes:
772+
// Minimum Cost Flows or the Max-Expected-Value (recently discussed with
773+
// Rene) or Dijkstra
774+
json_add_node_id(req->js, "source", &pay_plugin->my_id);
775+
json_add_node_id(req->js, "destination",
776+
&payment->payment_info.destination);
777+
json_add_amount_msat(req->js, "amount_msat", remaining);
778+
json_array_start(req->js, "layers");
779+
// FIXME: put here the layers that we use
780+
json_add_string(req->js, NULL, "auto.localchans");
781+
json_array_end(req->js);
782+
json_add_amount_msat(req->js, "maxfee_msat", feebudget);
783+
json_add_u32(req->js, "final_cltv", payment->payment_info.final_cltv);
784+
return send_outreq(cmd->plugin, req);
719785
}
720786

721787
REGISTER_PAYMENT_MODIFIER(compute_routes, compute_routes_cb);

0 commit comments

Comments
 (0)