Skip to content

Commit fe8e77f

Browse files
committed
renepay: use getroutes
Changelog-Added: renepay: use external call to [askrene-]getroutes instead of computing routes internally. Signed-off-by: Lagrang3 <[email protected]>
1 parent ee2f711 commit fe8e77f

File tree

3 files changed

+160
-56
lines changed

3 files changed

+160
-56
lines changed

plugins/renepay/json.c

+55
Original file line numberDiff line numberDiff line change
@@ -393,3 +393,58 @@ void json_myadd_blinded_path(struct json_stream *s,
393393
json_array_end(s);
394394
json_object_end(s);
395395
}
396+
397+
bool json_to_myroute(const char *buf,
398+
const jsmntok_t *tok,
399+
struct route *route)
400+
{
401+
u64 probability_ppm;
402+
u32 final_delay;
403+
const char *err = json_scan(
404+
tmpctx, buf, tok, "{probability_ppm:%,amount_msat:%,final_cltv:%}",
405+
JSON_SCAN(json_to_u64, &probability_ppm),
406+
JSON_SCAN(json_to_msat, &route->amount_deliver),
407+
JSON_SCAN(json_to_u32, &final_delay));
408+
409+
if (err)
410+
return false;
411+
route->success_prob = probability_ppm * 1e-6;
412+
const jsmntok_t *pathtok = json_get_member(buf, tok, "path");
413+
if (!pathtok || pathtok->size != JSMN_ARRAY)
414+
return false;
415+
416+
assert(route->hops == NULL);
417+
route->hops = tal_arr(route, struct route_hop, pathtok->size);
418+
size_t i;
419+
const jsmntok_t *hoptok;
420+
json_for_each_arr(i, hoptok, pathtok)
421+
{
422+
struct route_hop *hop = &route->hops[i];
423+
struct short_channel_id_dir scidd;
424+
struct amount_msat amount;
425+
u32 delay;
426+
err = json_scan(tmpctx, buf, hoptok,
427+
"{short_channel_id_dir:%,next_node_id:%,amount_msat:%,delay:%}",
428+
JSON_SCAN(json_to_short_channel_id_dir, &scidd),
429+
JSON_SCAN(json_to_node_id, &hop->node_id),
430+
JSON_SCAN(json_to_msat, &amount),
431+
JSON_SCAN(json_to_u32, &delay));
432+
if (err) {
433+
route->hops = tal_free(route->hops);
434+
return false;
435+
}
436+
hop->scid = scidd.scid;
437+
hop->direction = scidd.dir;
438+
439+
/* FIXME: this convention is so weird. If we ever get to merge
440+
* PR 7639, remember to remove this index adjustment. */
441+
if (i > 0) {
442+
route->hops[i - 1].amount = amount;
443+
route->hops[i - 1].delay = delay;
444+
}
445+
}
446+
route->hops[i - 1].amount = route->amount_deliver;
447+
route->hops[i - 1].delay = final_delay;
448+
route->amount_sent = route->hops[0].amount;
449+
return true;
450+
}

plugins/renepay/json.h

+4
Original file line numberDiff line numberDiff line change
@@ -25,4 +25,8 @@ void json_myadd_blinded_path(struct json_stream *s,
2525
const char *fieldname,
2626
const struct blinded_path *blinded_path);
2727

28+
bool json_to_myroute(const char *buf,
29+
const jsmntok_t *tok,
30+
struct route *route);
31+
2832
#endif /* LIGHTNING_PLUGINS_RENEPAY_JSON_H */

plugins/renepay/mods.c

+101-56
Original file line numberDiff line numberDiff line change
@@ -652,23 +652,79 @@ REGISTER_PAYMENT_MODIFIER(blindedhints, blindedhints_cb);
652652

653653

654654
/*****************************************************************************
655-
* compute_routes
655+
* getroutes
656656
*
657-
* Compute the payment routes.
657+
* Call askrene-getroutes
658658
*/
659659

660-
static struct command_result *compute_routes_cb(struct payment *payment)
660+
661+
static struct command_result *getroutes_done(struct command *cmd,
662+
const char *method,
663+
const char *buf,
664+
const jsmntok_t *tok,
665+
struct payment *payment)
661666
{
662-
assert(payment->status == PAYMENT_PENDING);
663667
struct routetracker *routetracker = payment->routetracker;
664668
assert(routetracker);
665669

666-
if (routetracker->computed_routes &&
667-
tal_count(routetracker->computed_routes))
670+
if (tal_count(routetracker->computed_routes) > 0)
668671
plugin_err(pay_plugin->plugin,
669672
"%s: no previously computed routes expected.",
670673
__func__);
671674

675+
routetracker->computed_routes = tal_free(routetracker->computed_routes);
676+
const jsmntok_t *routestok = json_get_member(buf, tok, "routes");
677+
assert(routestok && routestok->type == JSMN_ARRAY);
678+
routetracker->computed_routes =
679+
tal_arr(routetracker, struct route *, 0);
680+
681+
size_t i;
682+
const jsmntok_t *r;
683+
json_for_each_arr(i, r, routestok)
684+
{
685+
struct route *route = new_route(
686+
routetracker->computed_routes, payment->groupid,
687+
payment->next_partid++, payment->payment_info.payment_hash,
688+
AMOUNT_MSAT(0), AMOUNT_MSAT(0));
689+
tal_arr_expand(&routetracker->computed_routes, route);
690+
bool success = json_to_myroute(buf, r, route);
691+
if (!success) {
692+
plugin_err(
693+
pay_plugin->plugin,
694+
"%s: failed to parse route from getroutes, %.*s",
695+
__func__, json_tok_full_len(r),
696+
json_tok_full(buf, r));
697+
}
698+
assert(success);
699+
}
700+
return payment_continue(payment);
701+
}
702+
703+
static struct command_result *getroutes_fail(struct command *cmd,
704+
const char *method,
705+
const char *buf,
706+
const jsmntok_t *tok,
707+
struct payment *payment)
708+
{
709+
// FIXME: read the response
710+
// if can we do something about his failure:
711+
// disable channels or add biases
712+
// return payment_continue(payment);
713+
// else:
714+
// return payment_fail(payment, PAY_STOPPED_RETRYING, "getroutes
715+
// failed to find a feasible solution %s", explain_error(buf,
716+
// tok));
717+
const jsmntok_t *messtok = json_get_member(buf, tok, "message");
718+
assert(messtok);
719+
return payment_fail(
720+
payment, PAYMENT_PENDING,
721+
"getroutes failed to find a feasible solution: %.*s",
722+
json_tok_full_len(messtok), json_tok_full(buf, messtok));
723+
}
724+
725+
static struct command_result *getroutes_cb(struct payment *payment)
726+
{
727+
assert(payment->status == PAYMENT_PENDING);
672728
struct amount_msat feebudget, fees_spent, remaining;
673729

674730
/* Total feebudget */
@@ -699,57 +755,46 @@ static struct command_result *compute_routes_cb(struct payment *payment)
699755
return payment_continue(payment);
700756
}
701757

702-
enum jsonrpc_errcode errcode;
703-
const char *err_msg = NULL;
704-
705-
gossmap_apply_localmods(pay_plugin->gossmap, payment->local_gossmods);
706-
707-
/* get_routes returns the answer, we assign it to the computed_routes,
708-
* that's why we need to tal_free the older array. Maybe it would be
709-
* better to pass computed_routes as a reference? */
710-
routetracker->computed_routes = tal_free(routetracker->computed_routes);
711-
712-
/* Send get_routes a note that it should discard the last hop because we
713-
* are actually solving a multiple destinations problem. */
714-
bool blinded_destination = true;
715-
716-
// TODO: add an algorithm selector here
717-
/* We let this return an unlikely path, as it's better to try once than
718-
* simply refuse. Plus, models are not truth! */
719-
routetracker->computed_routes = get_routes(
720-
routetracker,
721-
&payment->payment_info,
722-
&pay_plugin->my_id,
723-
payment->routing_destination,
724-
pay_plugin->gossmap,
725-
pay_plugin->uncertainty,
726-
payment->disabledmap,
727-
remaining,
728-
feebudget,
729-
&payment->next_partid,
730-
payment->groupid,
731-
blinded_destination,
732-
&errcode,
733-
&err_msg);
734-
735-
/* Otherwise the error message remains a child of the routetracker. */
736-
err_msg = tal_steal(tmpctx, err_msg);
737-
738-
gossmap_remove_localmods(pay_plugin->gossmap, payment->local_gossmods);
739-
740-
/* Couldn't feasible route, we stop. */
741-
if (!routetracker->computed_routes ||
742-
tal_count(routetracker->computed_routes) == 0) {
743-
if (err_msg == NULL)
744-
err_msg = tal_fmt(
745-
tmpctx, "get_routes returned NULL error message");
746-
return payment_fail(payment, errcode, "%s", err_msg);
747-
}
748-
749-
return payment_continue(payment);
758+
/* FIXME:
759+
* call getroutes:
760+
* input: source, destination, amount, maxfee, final_cltv,
761+
* maxdelay, layers: [auto.localchans, auto.sourcefree,
762+
* thispaymenthints, thispaymentexclude, renepayknowledge]
763+
*
764+
* possible outcomes:
765+
* success: then continue
766+
* fail with hint: try to fix and retry or fail payment
767+
* */
768+
struct command *cmd = payment_command(payment);
769+
struct out_req *req = jsonrpc_request_start(
770+
cmd, "getroutes", getroutes_done, getroutes_fail, payment);
771+
772+
// FIXME: add an algorithm selection in askrene such that we could
773+
// retrieve a single path route if necessary, see issue 8042
774+
// FIXME: register layers before using then:
775+
// -> register RENEPAY_LAYER on plugin startup
776+
// -> register payment->payment_layer when payment is created
777+
// -> payment_layer should auto clean
778+
// -> register payment->command_layer when the payment execution
779+
// starts
780+
// -> command_layer should auto clean
781+
782+
json_add_node_id(req->js, "source", &pay_plugin->my_id);
783+
json_add_node_id(req->js, "destination", payment->routing_destination);
784+
json_add_amount_msat(req->js, "amount_msat", remaining);
785+
json_add_amount_msat(req->js, "maxfee_msat", feebudget);
786+
json_add_u32(req->js, "final_cltv", payment->payment_info.final_cltv);
787+
json_array_start(req->js, "layers");
788+
json_add_string(req->js, NULL, "auto.localchans");
789+
json_add_string(req->js, NULL, "auto.sourcefree");
790+
json_array_end(req->js);
791+
// FIXME: add further constraints here if necessary when they become
792+
// available in getroutes
793+
// eg. json_add_u32(req->js, "maxdelay", payment->payment_info.maxdelay);
794+
return send_outreq(req);
750795
}
751796

752-
REGISTER_PAYMENT_MODIFIER(compute_routes, compute_routes_cb);
797+
REGISTER_PAYMENT_MODIFIER(getroutes, getroutes_cb);
753798

754799
/*****************************************************************************
755800
* send_routes
@@ -1258,7 +1303,7 @@ void *payment_virtual_program[] = {
12581303
/*16*/ OP_CALL, &pendingsendpays_pay_mod,
12591304
/*18*/ OP_CALL, &checktimeout_pay_mod,
12601305
/*20*/ OP_CALL, &refreshgossmap_pay_mod,
1261-
/*22*/ OP_CALL, &compute_routes_pay_mod,
1306+
/*22*/ OP_CALL, &getroutes_pay_mod,
12621307
/*24*/ OP_CALL, &send_routes_pay_mod,
12631308
/*do*/
12641309
/*26*/ OP_CALL, &sleep_pay_mod,

0 commit comments

Comments
 (0)