Skip to content

Commit f75a73d

Browse files
committed
renepay: enable routing through blinded paths
Enable routing through blinded paths using fake channels in local gossmods. Changelog-None Signed-off-by: Lagrang3 <[email protected]>
1 parent 7ef7c77 commit f75a73d

File tree

9 files changed

+115
-23
lines changed

9 files changed

+115
-23
lines changed

plugins/renepay/main.c

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -343,6 +343,7 @@ static struct command_result *json_pay(struct command *cmd, const char *buf,
343343

344344
pinfo->blinded_paths = NULL;
345345
pinfo->blinded_payinfos = NULL;
346+
payment->routing_destination = &pinfo->destination;
346347
} else {
347348
pinfo->payment_secret = NULL;
348349
pinfo->routehints = NULL;
@@ -368,6 +369,18 @@ static struct command_result *json_pay(struct command *cmd, const char *buf,
368369
max_final_cltv = final_cltv;
369370
}
370371
pinfo->final_cltv = max_final_cltv;
372+
373+
/* When dealing with BOLT12 blinded paths we compute the
374+
* routing targeting a fake node to enable
375+
* multi-destination minimum-cost-flow. Every blinded
376+
* path entry node will be linked to this fake node
377+
* using fake channels as well. */
378+
payment->routing_destination =
379+
tal(payment, struct node_id);
380+
if (!node_id_from_hexstr(
381+
"02""0000000000000000000000000000000000000000000000000000000000000001",
382+
66, payment->routing_destination))
383+
abort();
371384
}
372385

373386
if (!payment_set_constraints(

plugins/renepay/mods.c

Lines changed: 73 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
#include <plugins/renepay/routebuilder.h>
1414
#include <plugins/renepay/routetracker.h>
1515
#include <unistd.h>
16+
#include <wire/bolt12_wiregen.h>
1617

1718
#define INVALID_ID UINT32_MAX
1819

@@ -515,7 +516,9 @@ REGISTER_PAYMENT_MODIFIER(refreshgossmap, refreshgossmap_cb);
515516
static void add_hintchan(struct payment *payment, const struct node_id *src,
516517
const struct node_id *dst, u16 cltv_expiry_delta,
517518
const struct short_channel_id scid, u32 fee_base_msat,
518-
u32 fee_proportional_millionths)
519+
u32 fee_proportional_millionths,
520+
const struct amount_msat *chan_htlc_min,
521+
const struct amount_msat *chan_htlc_max)
519522
{
520523
assert(payment);
521524
assert(payment->local_gossmods);
@@ -528,6 +531,12 @@ static void add_hintchan(struct payment *payment, const struct node_id *src,
528531
struct short_channel_id_dir scidd;
529532
/* We assume any HTLC is allowed */
530533
struct amount_msat htlc_min = AMOUNT_MSAT(0), htlc_max = MAX_CAPACITY;
534+
535+
if (chan_htlc_min)
536+
htlc_min = *chan_htlc_min;
537+
if (chan_htlc_max)
538+
htlc_max = *chan_htlc_max;
539+
531540
struct amount_msat fee_base = amount_msat(fee_base_msat);
532541
bool enabled = true;
533542
scidd.scid = scid;
@@ -604,7 +613,8 @@ static struct command_result *routehints_done(struct command *cmd UNUSED,
604613
add_hintchan(payment, &r[j].pubkey, end,
605614
r[j].cltv_expiry_delta,
606615
r[j].short_channel_id, r[j].fee_base_msat,
607-
r[j].fee_proportional_millionths);
616+
r[j].fee_proportional_millionths,
617+
NULL, NULL);
608618
end = &r[j].pubkey;
609619
}
610620
}
@@ -625,6 +635,8 @@ static struct command_result *routehints_done(struct command *cmd UNUSED,
625635

626636
static struct command_result *routehints_cb(struct payment *payment)
627637
{
638+
if (payment->payment_info.routehints == NULL)
639+
return payment_continue(payment);
628640
struct command *cmd = payment_command(payment);
629641
assert(cmd);
630642
struct out_req *req = jsonrpc_request_start(
@@ -636,6 +648,44 @@ static struct command_result *routehints_cb(struct payment *payment)
636648

637649
REGISTER_PAYMENT_MODIFIER(routehints, routehints_cb);
638650

651+
652+
/*****************************************************************************
653+
* blindedhints
654+
*
655+
* Similar to routehints but for bolt12 invoices: create fake channel that
656+
* connect the blinded path entry point to the destination node.
657+
*/
658+
659+
static struct command_result *blindedhints_cb(struct payment *payment)
660+
{
661+
if (payment->payment_info.blinded_paths == NULL)
662+
return payment_continue(payment);
663+
664+
struct payment_info *pinfo = &payment->payment_info;
665+
struct short_channel_id scid;
666+
struct node_id src;
667+
668+
for (size_t i = 0; i < tal_count(pinfo->blinded_paths); i++) {
669+
const struct blinded_payinfo *payinfo =
670+
pinfo->blinded_payinfos[i];
671+
const struct blinded_path *path = pinfo->blinded_paths[i];
672+
673+
scid.u64 = i; // a fake scid
674+
node_id_from_pubkey(&src, &path->first_node_id.pubkey);
675+
676+
add_hintchan(payment, &src, payment->routing_destination,
677+
payinfo->cltv_expiry_delta, scid,
678+
payinfo->fee_base_msat,
679+
payinfo->fee_proportional_millionths,
680+
&payinfo->htlc_minimum_msat,
681+
&payinfo->htlc_maximum_msat);
682+
}
683+
return payment_continue(payment);
684+
}
685+
686+
REGISTER_PAYMENT_MODIFIER(blindedhints, blindedhints_cb);
687+
688+
639689
/*****************************************************************************
640690
* compute_routes
641691
*
@@ -694,23 +744,30 @@ static struct command_result *compute_routes_cb(struct payment *payment)
694744
* better to pass computed_routes as a reference? */
695745
routetracker->computed_routes = tal_free(routetracker->computed_routes);
696746

747+
/* Send get_routes a note that it should discard the last hop because we
748+
* are actually solving a multiple destinations problem. */
749+
bool blinded_destination =
750+
payment->payment_info.blinded_paths != NULL;
751+
697752
// TODO: add an algorithm selector here
698753
/* We let this return an unlikely path, as it's better to try once than
699754
* simply refuse. Plus, models are not truth! */
700755
routetracker->computed_routes = get_routes(
701756
routetracker,
702757
&payment->payment_info,
703758
&pay_plugin->my_id,
704-
&payment->payment_info.destination,
759+
payment->routing_destination,
705760
pay_plugin->gossmap,
706761
pay_plugin->uncertainty,
707762
payment->disabledmap,
708763
remaining,
709764
feebudget,
710765
&payment->next_partid,
711766
payment->groupid,
767+
blinded_destination,
712768
&errcode,
713769
&err_msg);
770+
714771
/* Otherwise the error message remains a child of the routetracker. */
715772
err_msg = tal_steal(tmpctx, err_msg);
716773

@@ -1230,20 +1287,21 @@ void *payment_virtual_program[] = {
12301287
/*6*/ OP_CALL, &getmychannels_pay_mod,
12311288
/*8*/ OP_CALL, &refreshgossmap_pay_mod,
12321289
/*10*/ OP_CALL, &routehints_pay_mod,
1233-
/*12*/OP_CALL, &channelfilter_pay_mod,
1290+
/*12*/ OP_CALL, &blindedhints_pay_mod,
1291+
/*14*/OP_CALL, &channelfilter_pay_mod,
12341292
// TODO shadow_additions
12351293
/* do */
1236-
/*14*/ OP_CALL, &pendingsendpays_pay_mod,
1237-
/*16*/ OP_CALL, &checktimeout_pay_mod,
1238-
/*18*/ OP_CALL, &refreshgossmap_pay_mod,
1239-
/*20*/ OP_CALL, &compute_routes_pay_mod,
1240-
/*22*/ OP_CALL, &send_routes_pay_mod,
1294+
/*16*/ OP_CALL, &pendingsendpays_pay_mod,
1295+
/*18*/ OP_CALL, &checktimeout_pay_mod,
1296+
/*20*/ OP_CALL, &refreshgossmap_pay_mod,
1297+
/*22*/ OP_CALL, &compute_routes_pay_mod,
1298+
/*24*/ OP_CALL, &send_routes_pay_mod,
12411299
/*do*/
1242-
/*24*/ OP_CALL, &sleep_pay_mod,
1243-
/*26*/ OP_CALL, &collect_results_pay_mod,
1300+
/*26*/ OP_CALL, &sleep_pay_mod,
1301+
/*28*/ OP_CALL, &collect_results_pay_mod,
12441302
/*while*/
1245-
/*28*/ OP_IF, &nothaveresults_pay_cond, (void *)24,
1303+
/*30*/ OP_IF, &nothaveresults_pay_cond, (void *)26,
12461304
/* while */
1247-
/*31*/ OP_IF, &retry_pay_cond, (void *)14,
1248-
/*34*/ OP_CALL, &end_pay_mod, /* safety net, default failure if reached */
1249-
/*36*/ NULL};
1305+
/*33*/ OP_IF, &retry_pay_cond, (void *)16,
1306+
/*36*/ OP_CALL, &end_pay_mod, /* safety net, default failure if reached */
1307+
/*38*/ NULL};

plugins/renepay/payment.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,10 @@ struct payment {
5656
/* Localmods to apply to gossip_map for our own use. */
5757
struct gossmap_localmods *local_gossmods;
5858

59+
/* Routes will be computed to reach this node, could be a fake node that
60+
* we use to handle multiple blinded paths. */
61+
struct node_id *routing_destination;
62+
5963
struct disabledmap *disabledmap;
6064

6165
/* Flag to indicate wether we have collected enough results to make a

plugins/renepay/route.c

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ struct route *new_route(const tal_t *ctx, u32 groupid,
1919

2020
route->amount = amount;
2121
route->amount_sent = amount_sent;
22+
route->path_num = -1;
2223
return route;
2324
}
2425

@@ -32,7 +33,8 @@ struct route *new_route(const tal_t *ctx, u32 groupid,
3233
struct route *flow_to_route(const tal_t *ctx,
3334
u32 groupid, u32 partid, struct sha256 payment_hash,
3435
u32 final_cltv, struct gossmap *gossmap,
35-
struct flow *flow)
36+
struct flow *flow,
37+
bool blinded_destination)
3638
{
3739
struct route *route =
3840
new_route(ctx, groupid, partid, payment_hash,
@@ -67,6 +69,12 @@ struct route *flow_to_route(const tal_t *ctx,
6769
route->success_prob = flow->success_prob;
6870
route->amount = route->hops[pathlen - 1].amount;
6971
route->amount_sent = route->hops[0].amount;
72+
73+
if (blinded_destination) {
74+
route->path_num = route->hops[pathlen - 1].scid.u64;
75+
tal_arr_remove(&route->hops, pathlen - 1);
76+
}
77+
7078
return route;
7179

7280
function_fail:
@@ -85,7 +93,8 @@ struct route **flows_to_routes(const tal_t *ctx,
8593
for (size_t i = 0; i < N; i++) {
8694
routes[i] =
8795
flow_to_route(routes, groupid, partid++,
88-
payment_hash, final_cltv, gossmap, flows[i]);
96+
payment_hash, final_cltv, gossmap, flows[i],
97+
false);
8998
if (!routes[i])
9099
goto function_fail;
91100
}

plugins/renepay/route.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,9 @@ struct route {
6868

6969
/* result of waitsenday */
7070
struct payment_result *result;
71+
72+
/* blinded path index if any */
73+
int path_num;
7174
};
7275

7376
static inline struct routekey routekey(const struct sha256 *hash, u64 groupid,
@@ -117,7 +120,8 @@ struct route *new_route(const tal_t *ctx, u32 groupid,
117120
struct route *flow_to_route(const tal_t *ctx,
118121
u32 groupid, u32 partid, struct sha256 payment_hash,
119122
u32 final_cltv, struct gossmap *gossmap,
120-
struct flow *flow);
123+
struct flow *flow,
124+
bool blinded_destination);
121125

122126
struct route **flows_to_routes(const tal_t *ctx,
123127
u32 groupid, u32 partid,

plugins/renepay/routebuilder.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,7 @@ struct route **get_routes(const tal_t *ctx,
140140

141141
u64 *next_partid,
142142
u64 groupid,
143+
bool blinded_destination,
143144

144145
enum jsonrpc_errcode *ecode,
145146
const char **fail)
@@ -297,7 +298,8 @@ struct route **get_routes(const tal_t *ctx,
297298
struct route *r = flow_to_route(
298299
this_ctx, groupid, *next_partid,
299300
payment_info->payment_hash,
300-
payment_info->final_cltv, gossmap, flows[i]);
301+
payment_info->final_cltv, gossmap, flows[i],
302+
blinded_destination);
301303

302304
if (!r) {
303305
tal_report_error(

plugins/renepay/routebuilder.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ struct route **get_routes(const tal_t *ctx,
2323

2424
u64 *next_partid,
2525
u64 groupid,
26+
bool blinded_destination,
2627

2728
enum jsonrpc_errcode *ecode,
2829
const char **fail);

plugins/renepay/test/run-bottleneck.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -263,6 +263,7 @@ int main(int argc, char *argv[])
263263
/* feebudget */maxfee,
264264
&next_partid,
265265
groupid,
266+
false,
266267
&errcode,
267268
&err_msg);
268269

plugins/renepay/test/run-testflow.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -691,7 +691,7 @@ static void test_flow_to_route(void)
691691
F->dirs[0]=0;
692692
deliver = AMOUNT_MSAT(250000000);
693693
F->amount = deliver;
694-
route = flow_to_route(this_ctx, 1, 1, payment_hash, 0, gossmap, F);
694+
route = flow_to_route(this_ctx, 1, 1, payment_hash, 0, gossmap, F, false);
695695
assert(route);
696696

697697
assert(amount_msat_eq(route->hops[0].amount, deliver));
@@ -707,7 +707,7 @@ static void test_flow_to_route(void)
707707
F->dirs[1]=0;
708708
deliver = AMOUNT_MSAT(250000000);
709709
F->amount=deliver;
710-
route = flow_to_route(this_ctx, 1, 1, payment_hash, 0, gossmap, F);
710+
route = flow_to_route(this_ctx, 1, 1, payment_hash, 0, gossmap, F, false);
711711
assert(route);
712712

713713
assert(amount_msat_eq(route->hops[0].amount, amount_msat(250050016)));
@@ -725,7 +725,7 @@ static void test_flow_to_route(void)
725725
F->dirs[2]=0;
726726
deliver = AMOUNT_MSAT(250000000);
727727
F->amount=deliver;
728-
route = flow_to_route(this_ctx, 1, 1, payment_hash, 0, gossmap, F);
728+
route = flow_to_route(this_ctx, 1, 1, payment_hash, 0, gossmap, F, false);
729729
assert(route);
730730

731731
assert(amount_msat_eq(route->hops[0].amount, amount_msat(250087534)));
@@ -745,7 +745,7 @@ static void test_flow_to_route(void)
745745
F->dirs[3]=0;
746746
deliver = AMOUNT_MSAT(250000000);
747747
F->amount=deliver;
748-
route = flow_to_route(this_ctx, 1, 1, payment_hash, 0, gossmap, F);
748+
route = flow_to_route(this_ctx, 1, 1, payment_hash, 0, gossmap, F, false);
749749
assert(route);
750750

751751
assert(amount_msat_eq(route->hops[0].amount, amount_msat(250112544)));

0 commit comments

Comments
 (0)