Skip to content

Commit 2fddfba

Browse files
committed
renepay: use batches to send payment routes
Sending requests with batches allow us to avoid race conditions when the payment plugin goes to the next state before the sendpay RPC have not yet completed. Changelog-None Signed-off-by: Lagrang3 <[email protected]>
1 parent 2507a50 commit 2fddfba

File tree

3 files changed

+156
-154
lines changed

3 files changed

+156
-154
lines changed

plugins/renepay/mods.c

Lines changed: 144 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -595,6 +595,146 @@ REGISTER_PAYMENT_MODIFIER(getroutes, getroutes_cb);
595595
* request calling sendpay.
596596
*/
597597

598+
static struct command_result *sendroutes_done(struct command *cmd,
599+
struct payment *payment)
600+
{
601+
return payment_continue(payment);
602+
}
603+
604+
/* Callback function for sendpay request success. */
605+
static struct command_result *
606+
renesendpay_done(struct command *cmd, const char *method UNUSED,
607+
const char *buf, const jsmntok_t *result, struct route *route)
608+
{
609+
assert(route);
610+
struct renepay *renepay = get_renepay(cmd->plugin);
611+
struct payment *payment = route_get_payment_verify(renepay, route);
612+
route_pending_register(payment, payment->routetracker, route);
613+
614+
const jsmntok_t *t;
615+
size_t i;
616+
bool ret;
617+
618+
const jsmntok_t *secretstok =
619+
json_get_member(buf, result, "shared_secrets");
620+
621+
if (secretstok) {
622+
assert(secretstok->type == JSMN_ARRAY);
623+
624+
route->shared_secrets =
625+
tal_arr(route, struct secret, secretstok->size);
626+
json_for_each_arr(i, t, secretstok)
627+
{
628+
ret = json_to_secret(buf, t, &route->shared_secrets[i]);
629+
assert(ret);
630+
}
631+
} else
632+
route->shared_secrets = NULL;
633+
return command_still_pending(cmd);
634+
}
635+
636+
/* FIXME: check when will renesendpay fail */
637+
static struct command_result *
638+
renesendpay_fail(struct command *cmd, const char *method UNUSED,
639+
const char *buf, const jsmntok_t *tok, struct route *route)
640+
{
641+
assert(route);
642+
struct renepay *renepay = get_renepay(cmd->plugin);
643+
struct payment *payment = route_get_payment_verify(renepay, route);
644+
struct routetracker *routetracker = payment->routetracker;
645+
assert(routetracker);
646+
647+
enum jsonrpc_errcode errcode;
648+
const char *msg;
649+
const char *err;
650+
651+
err = json_scan(tmpctx, buf, tok, "{code:%,message:%}",
652+
JSON_SCAN(json_to_jsonrpc_errcode, &errcode),
653+
JSON_SCAN_TAL(tmpctx, json_strdup, &msg));
654+
if (err)
655+
plugin_err(cmd->plugin,
656+
"Unable to parse sendpay error: %s, json: %.*s", err,
657+
json_tok_full_len(tok), json_tok_full(buf, tok));
658+
659+
payment_note(payment, LOG_INFORM,
660+
"Sendpay failed: partid=%" PRIu64
661+
" errorcode:%d message=%s",
662+
route->key.partid, errcode, msg);
663+
664+
if (errcode != PAY_TRY_OTHER_ROUTE) {
665+
plugin_log(cmd->plugin, LOG_UNUSUAL,
666+
"Strange error from sendpay: %.*s",
667+
json_tok_full_len(tok), json_tok_full(buf, tok));
668+
}
669+
670+
/* There is no new knowledge from this kind of failure.
671+
* We just disable this scid. */
672+
// FIXME: askrene disable this channel
673+
struct short_channel_id_dir scidd_disable = {
674+
.scid = route->hops[0].scid, .dir = route->hops[0].direction};
675+
payment_disable_chan(payment, scidd_disable, LOG_INFORM,
676+
"sendpay didn't like first hop: %s", msg);
677+
678+
if (!route_map_del(routetracker->sent_routes, route))
679+
plugin_err(cmd->plugin, "%s: route (%s) is not marked as sent",
680+
__func__, fmt_routekey(tmpctx, &route->key));
681+
tal_free(route);
682+
return command_still_pending(cmd);
683+
}
684+
685+
static void add_sendpay_request(struct rpcbatch *batch, struct route *route,
686+
struct payment *payment)
687+
{
688+
struct payment_info *pinfo = &payment->payment_info;
689+
struct out_req *req = add_to_rpcbatch(
690+
batch, "renesendpay", renesendpay_done, renesendpay_fail, route);
691+
const size_t pathlen = tal_count(route->hops);
692+
json_add_sha256(req->js, "payment_hash", &route->key.payment_hash);
693+
json_add_u64(req->js, "partid", route->key.partid);
694+
json_add_u64(req->js, "groupid", route->key.groupid);
695+
json_add_string(req->js, "invoice", pinfo->invstr);
696+
json_add_node_id(req->js, "destination", &pinfo->destination);
697+
json_add_amount_msat(req->js, "amount_msat", route->amount_deliver);
698+
json_add_amount_msat(req->js, "total_amount_msat", pinfo->amount);
699+
json_add_u32(req->js, "final_cltv", pinfo->final_cltv);
700+
701+
if (pinfo->label)
702+
json_add_string(req->js, "label", pinfo->label);
703+
if (pinfo->description)
704+
json_add_string(req->js, "description", pinfo->description);
705+
706+
json_array_start(req->js, "route");
707+
/* An empty route means a payment to oneself, pathlen=0 */
708+
for (size_t j = 0; j < pathlen; j++) {
709+
const struct route_hop *hop = &route->hops[j];
710+
json_object_start(req->js, NULL);
711+
json_add_node_id(req->js, "id", &hop->node_id);
712+
json_add_short_channel_id(req->js, "channel", hop->scid);
713+
json_add_amount_msat(req->js, "amount_msat", hop->amount);
714+
json_add_num(req->js, "direction", hop->direction);
715+
json_add_u32(req->js, "delay", hop->delay);
716+
json_add_string(req->js, "style", "tlv");
717+
json_object_end(req->js);
718+
}
719+
json_array_end(req->js);
720+
721+
/* Either we have a payment_secret for BOLT11 or blinded_paths for
722+
* BOLT12 */
723+
if (pinfo->payment_secret)
724+
json_add_secret(req->js, "payment_secret",
725+
pinfo->payment_secret);
726+
else {
727+
assert(pinfo->blinded_paths);
728+
const struct blinded_path *bpath =
729+
pinfo->blinded_paths[route->path_num];
730+
json_myadd_blinded_path(req->js, "blinded_path", bpath);
731+
}
732+
send_outreq(req);
733+
route_map_add(payment->routetracker->sent_routes, route);
734+
if (taken(route))
735+
tal_steal(payment->routetracker->sent_routes, route);
736+
}
737+
598738
static struct command_result *send_routes_cb(struct payment *payment)
599739
{
600740
assert(payment);
@@ -609,11 +749,11 @@ static struct command_result *send_routes_cb(struct payment *payment)
609749
}
610750
struct command *cmd = payment_command(payment);
611751
assert(cmd);
752+
struct rpcbatch *batch = rpcbatch_new(cmd, sendroutes_done, payment);
753+
612754
for (size_t i = 0; i < tal_count(routetracker->computed_routes); i++) {
613755
struct route *route = routetracker->computed_routes[i];
614-
615-
route_sendpay_request(cmd, take(route), payment);
616-
756+
add_sendpay_request(batch, take(route), payment);
617757
payment_note(payment, LOG_INFORM,
618758
"Sent route request: partid=%" PRIu64
619759
" amount=%s prob=%.3lf fees=%s delay=%u path=%s",
@@ -624,7 +764,7 @@ static struct command_result *send_routes_cb(struct payment *payment)
624764
route_delay(route), fmt_route_path(tmpctx, route));
625765
}
626766
tal_resize(&routetracker->computed_routes, 0);
627-
return payment_continue(payment);
767+
return rpcbatch_done(batch);
628768
}
629769

630770
REGISTER_PAYMENT_MODIFIER(send_routes, send_routes_cb);

plugins/renepay/routetracker.c

Lines changed: 5 additions & 150 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@
77
#include <plugins/renepay/routetracker.h>
88
#include <plugins/renepay/utils.h>
99

10-
static struct payment *route_get_payment_verify(struct renepay *renepay,
11-
struct route *route)
10+
struct payment *route_get_payment_verify(struct renepay *renepay,
11+
struct route *route)
1212
{
1313
struct payment *payment =
1414
payment_map_get(renepay->payment_map, route->key.payment_hash);
@@ -98,9 +98,9 @@ static void remove_route(struct route *route, struct route_map *map)
9898
* - after a sendpay is accepted,
9999
* - or after listsendpays reveals some pending route that we didn't
100100
* previously know about. */
101-
static void route_pending_register(struct payment *payment,
102-
struct routetracker *routetracker,
103-
struct route *route)
101+
void route_pending_register(struct payment *payment,
102+
struct routetracker *routetracker,
103+
struct route *route)
104104
{
105105
assert(route);
106106
assert(routetracker);
@@ -140,95 +140,6 @@ static void route_pending_register(struct payment *payment,
140140
}
141141
}
142142

143-
/* Callback function for sendpay request success. */
144-
static struct command_result *sendpay_done(struct command *cmd,
145-
const char *method UNUSED,
146-
const char *buf,
147-
const jsmntok_t *result,
148-
struct route *route)
149-
{
150-
assert(route);
151-
struct renepay *renepay = get_renepay(cmd->plugin);
152-
struct payment *payment = route_get_payment_verify(renepay, route);
153-
route_pending_register(payment, payment->routetracker, route);
154-
155-
const jsmntok_t *t;
156-
size_t i;
157-
bool ret;
158-
159-
const jsmntok_t *secretstok =
160-
json_get_member(buf, result, "shared_secrets");
161-
162-
if (secretstok) {
163-
assert(secretstok->type == JSMN_ARRAY);
164-
165-
route->shared_secrets =
166-
tal_arr(route, struct secret, secretstok->size);
167-
json_for_each_arr(i, t, secretstok)
168-
{
169-
ret = json_to_secret(buf, t, &route->shared_secrets[i]);
170-
assert(ret);
171-
}
172-
} else
173-
route->shared_secrets = NULL;
174-
return command_still_pending(cmd);
175-
}
176-
177-
/* sendpay really only fails immediately in two ways:
178-
* 1. We screwed up and misused the API.
179-
* 2. The first peer is disconnected.
180-
*/
181-
static struct command_result *sendpay_failed(struct command *cmd,
182-
const char *method UNUSED,
183-
const char *buf,
184-
const jsmntok_t *tok,
185-
struct route *route)
186-
{
187-
assert(route);
188-
struct renepay *renepay = get_renepay(cmd->plugin);
189-
struct payment *payment = route_get_payment_verify(renepay, route);
190-
struct routetracker *routetracker = payment->routetracker;
191-
assert(routetracker);
192-
193-
enum jsonrpc_errcode errcode;
194-
const char *msg;
195-
const char *err;
196-
197-
err = json_scan(tmpctx, buf, tok, "{code:%,message:%}",
198-
JSON_SCAN(json_to_jsonrpc_errcode, &errcode),
199-
JSON_SCAN_TAL(tmpctx, json_strdup, &msg));
200-
if (err)
201-
plugin_err(cmd->plugin,
202-
"Unable to parse sendpay error: %s, json: %.*s", err,
203-
json_tok_full_len(tok), json_tok_full(buf, tok));
204-
205-
payment_note(payment, LOG_INFORM,
206-
"Sendpay failed: partid=%" PRIu64
207-
" errorcode:%d message=%s",
208-
route->key.partid, errcode, msg);
209-
210-
if (errcode != PAY_TRY_OTHER_ROUTE) {
211-
plugin_log(cmd->plugin, LOG_UNUSUAL,
212-
"Strange error from sendpay: %.*s",
213-
json_tok_full_len(tok), json_tok_full(buf, tok));
214-
}
215-
216-
/* There is no new knowledge from this kind of failure.
217-
* We just disable this scid. */
218-
struct short_channel_id_dir scidd_disable = {
219-
.scid = route->hops[0].scid, .dir = route->hops[0].direction};
220-
payment_disable_chan(payment, scidd_disable, LOG_INFORM,
221-
"sendpay didn't like first hop: %s", msg);
222-
223-
if (!route_map_del(routetracker->sent_routes, route))
224-
plugin_err(cmd->plugin,
225-
"%s: route (%s) is not marked as sent",
226-
__func__,
227-
fmt_routekey(tmpctx, &route->key));
228-
tal_free(route);
229-
return command_still_pending(cmd);
230-
}
231-
232143
void payment_collect_results(struct payment *payment,
233144
struct preimage **payment_preimage,
234145
enum jsonrpc_errcode *final_error,
@@ -296,62 +207,6 @@ void payment_collect_results(struct payment *payment,
296207
tal_resize(&routetracker->finalized_routes, 0);
297208
}
298209

299-
struct command_result *route_sendpay_request(struct command *cmd,
300-
struct route *route TAKES,
301-
struct payment *payment)
302-
{
303-
const struct payment_info *pinfo = &payment->payment_info;
304-
struct out_req *req = jsonrpc_request_start(
305-
cmd, "renesendpay", sendpay_done, sendpay_failed, route);
306-
307-
const size_t pathlen = tal_count(route->hops);
308-
json_add_sha256(req->js, "payment_hash", &pinfo->payment_hash);
309-
json_add_u64(req->js, "partid", route->key.partid);
310-
json_add_u64(req->js, "groupid", route->key.groupid);
311-
json_add_string(req->js, "invoice", pinfo->invstr);
312-
json_add_node_id(req->js, "destination", &pinfo->destination);
313-
json_add_amount_msat(req->js, "amount_msat", route->amount_deliver);
314-
json_add_amount_msat(req->js, "total_amount_msat", pinfo->amount);
315-
json_add_u32(req->js, "final_cltv", pinfo->final_cltv);
316-
317-
if (pinfo->label)
318-
json_add_string(req->js, "label", pinfo->label);
319-
if (pinfo->description)
320-
json_add_string(req->js, "description", pinfo->description);
321-
322-
json_array_start(req->js, "route");
323-
/* An empty route means a payment to oneself, pathlen=0 */
324-
for (size_t j = 0; j < pathlen; j++) {
325-
const struct route_hop *hop = &route->hops[j];
326-
json_object_start(req->js, NULL);
327-
json_add_node_id(req->js, "id", &hop->node_id);
328-
json_add_short_channel_id(req->js, "channel", hop->scid);
329-
json_add_amount_msat(req->js, "amount_msat", hop->amount);
330-
json_add_num(req->js, "direction", hop->direction);
331-
json_add_u32(req->js, "delay", hop->delay);
332-
json_add_string(req->js, "style", "tlv");
333-
json_object_end(req->js);
334-
}
335-
json_array_end(req->js);
336-
337-
/* Either we have a payment_secret for BOLT11 or blinded_paths for
338-
* BOLT12 */
339-
if (pinfo->payment_secret)
340-
json_add_secret(req->js, "payment_secret", pinfo->payment_secret);
341-
else {
342-
assert(pinfo->blinded_paths);
343-
const struct blinded_path *bpath =
344-
pinfo->blinded_paths[route->path_num];
345-
json_myadd_blinded_path(req->js, "blinded_path", bpath);
346-
347-
}
348-
349-
route_map_add(payment->routetracker->sent_routes, route);
350-
if (taken(route))
351-
tal_steal(payment->routetracker->sent_routes, route);
352-
return send_outreq(req);
353-
}
354-
355210
struct command_result *notification_sendpay_failure(struct command *cmd,
356211
const char *buf,
357212
const jsmntok_t *params)

plugins/renepay/routetracker.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,13 @@ void routetracker_add_to_final(struct payment *payment,
5151
struct routetracker *routetracker,
5252
struct route *route);
5353

54+
void route_pending_register(struct payment *payment,
55+
struct routetracker *routetracker,
56+
struct route *route);
57+
58+
struct payment *route_get_payment_verify(struct renepay *renepay,
59+
struct route *route);
60+
5461
// FIXME: double-check that we actually get one notification for each sendpay,
5562
// ie. that after some time we don't have yet pending sendpays for old failed or
5663
// successful payments that we havent processed because we haven't received the

0 commit comments

Comments
 (0)