Skip to content

Commit 8147933

Browse files
committed
renepay: decode error onion
When paying with injectpaymentonion we need to manually decode the error from the onion. Changelog-None. Signed-off-by: Lagrang3 <[email protected]>
1 parent d89e58d commit 8147933

File tree

4 files changed

+161
-86
lines changed

4 files changed

+161
-86
lines changed

plugins/renepay/json.c

+101-74
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
#include "config.h"
22
#include <common/json_stream.h>
3+
#include <common/onionreply.h>
4+
#include <common/sphinx.h>
35
#include <plugins/renepay/json.h>
46

57
/* See if this notification is about one of our flows. */
@@ -72,12 +74,103 @@ struct route *tal_route_from_json(const tal_t *ctx, const char *buf,
7274
return tal_free(route);
7375
}
7476

77+
static bool get_data_details_onionreply(struct payment_result *result,
78+
const char *buffer,
79+
const jsmntok_t *datatok,
80+
struct secret *shared_secrets)
81+
{
82+
const tal_t *this_ctx = tal(result, tal_t);
83+
const jsmntok_t *onionreplytok;
84+
struct onionreply *onionreply, *wonionreply;
85+
const u8 *replymsg;
86+
int index;
87+
88+
onionreplytok = json_get_member(buffer, datatok, "onionreply");
89+
if (!onionreplytok || !shared_secrets)
90+
goto fail;
91+
onionreply = new_onionreply(
92+
this_ctx,
93+
take(json_tok_bin_from_hex(this_ctx, buffer, onionreplytok)));
94+
assert(onionreply);
95+
/* FIXME: It seems that lightningd will unwrap top portion of the
96+
* onionreply for us before serializing it, while unwrap_onionreply will
97+
* try to do the entire unwraping. It would be a better API if either
98+
* lightningd unwraps the entire thing or it doesn't do any unwraping.
99+
* Also it wouldn't hurt if injectpaymentonion accepted the shared
100+
* secrets to allow lightningd do the decoding for us. */
101+
wonionreply = wrap_onionreply(this_ctx, &shared_secrets[0], onionreply);
102+
replymsg = unwrap_onionreply(this_ctx, shared_secrets,
103+
tal_count(shared_secrets),
104+
wonionreply, &index);
105+
if (replymsg) {
106+
result->failcode = tal(result, enum onion_wire);
107+
*result->failcode = fromwire_peektype(replymsg);
108+
109+
result->erring_index = tal(result, u32);
110+
*result->erring_index = index;
111+
}
112+
tal_free(this_ctx);
113+
return true;
114+
fail:
115+
tal_free(this_ctx);
116+
return false;
117+
}
118+
119+
static bool get_data_details(struct payment_result *result,
120+
const char *buffer,
121+
const jsmntok_t *datatok)
122+
{
123+
124+
const jsmntok_t *erridxtok, *failcodetok, *errnodetok, *errchantok,
125+
*errdirtok, *rawmsgtok, *failcodenametok;
126+
erridxtok = json_get_member(buffer, datatok, "erring_index");
127+
failcodetok = json_get_member(buffer, datatok, "failcode");
128+
129+
if (!erridxtok || !failcodetok)
130+
return false;
131+
result->failcode = tal(result, enum onion_wire);
132+
json_to_u32(buffer, failcodetok, result->failcode);
133+
134+
result->erring_index = tal(result, u32);
135+
json_to_u32(buffer, erridxtok, result->erring_index);
136+
137+
// search for other fields
138+
errnodetok = json_get_member(buffer, datatok, "erring_node");
139+
errchantok = json_get_member(buffer, datatok, "erring_channel");
140+
errdirtok = json_get_member(buffer, datatok, "erring_direction");
141+
failcodenametok = json_get_member(buffer, datatok, "failcodename");
142+
rawmsgtok = json_get_member(buffer, datatok, "raw_message");
143+
144+
if (errnodetok != NULL) {
145+
result->erring_node = tal(result, struct node_id);
146+
json_to_node_id(buffer, errnodetok, result->erring_node);
147+
}
148+
149+
if (errchantok != NULL) {
150+
result->erring_channel = tal(result, struct short_channel_id);
151+
json_to_short_channel_id(buffer, errchantok,
152+
result->erring_channel);
153+
}
154+
if (errdirtok != NULL) {
155+
result->erring_direction = tal(result, int);
156+
json_to_int(buffer, errdirtok, result->erring_direction);
157+
}
158+
if (rawmsgtok != NULL)
159+
result->raw_message =
160+
json_tok_bin_from_hex(result, buffer, rawmsgtok);
161+
162+
if (failcodenametok != NULL)
163+
result->failcodename =
164+
json_strdup(result, buffer, failcodenametok);
165+
166+
return true;
167+
}
168+
75169
struct payment_result *tal_sendpay_result_from_json(const tal_t *ctx,
76170
const char *buffer,
77-
const jsmntok_t *toks)
171+
const jsmntok_t *toks,
172+
struct secret *shared_secrets)
78173
{
79-
// FIXME: we will be getting onionreply try to decode these with
80-
// shared_secrets
81174
const jsmntok_t *idtok = json_get_member(buffer, toks, "created_index");
82175
const jsmntok_t *hashtok =
83176
json_get_member(buffer, toks, "payment_hash");
@@ -89,8 +182,6 @@ struct payment_result *tal_sendpay_result_from_json(const tal_t *ctx,
89182
const jsmntok_t *codetok = json_get_member(buffer, toks, "code");
90183
const jsmntok_t *msgtok = json_get_member(buffer, toks, "message");
91184
const jsmntok_t *datatok = json_get_member(buffer, toks, "data");
92-
const jsmntok_t *erridxtok, *failcodetok, *rawmsgtok,
93-
*failcodenametok, *errchantok, *errnodetok, *errdirtok;
94185
struct payment_result *result;
95186

96187
/* Check if we have an error and need to descend into data to get
@@ -110,6 +201,7 @@ struct payment_result *tal_sendpay_result_from_json(const tal_t *ctx,
110201
}
111202

112203
result = tal(ctx, struct payment_result);
204+
memset(result, 0, sizeof(struct payment_result));
113205

114206
if (msgtok)
115207
result->message = json_strdup(result, buffer, msgtok);
@@ -147,77 +239,12 @@ struct payment_result *tal_sendpay_result_from_json(const tal_t *ctx,
147239

148240
/* Now extract the error details if the error code is not 0 */
149241
if (result->code != 0 && datatok) {
150-
erridxtok = json_get_member(buffer, datatok, "erring_index");
151-
errnodetok = json_get_member(buffer, datatok, "erring_node");
152-
errchantok = json_get_member(buffer, datatok, "erring_channel");
153-
errdirtok =
154-
json_get_member(buffer, datatok, "erring_direction");
155-
failcodetok = json_get_member(buffer, datatok, "failcode");
156-
failcodenametok =
157-
json_get_member(buffer, datatok, "failcodename");
158-
rawmsgtok = json_get_member(buffer, datatok, "raw_message");
159-
/* check type for sanity */
160-
if ((failcodetok != NULL &&
161-
failcodetok->type != JSMN_PRIMITIVE) ||
162-
(failcodenametok != NULL &&
163-
failcodenametok->type != JSMN_STRING) ||
164-
(erridxtok != NULL && erridxtok->type != JSMN_PRIMITIVE) ||
165-
(errnodetok != NULL && errnodetok->type != JSMN_STRING) ||
166-
(errchantok != NULL && errchantok->type != JSMN_STRING) ||
167-
(errdirtok != NULL && errdirtok->type != JSMN_PRIMITIVE) ||
168-
(rawmsgtok != NULL && rawmsgtok->type != JSMN_STRING))
242+
/* try one, then try the other, then fail */
243+
if (!get_data_details(result, buffer, datatok) &&
244+
!get_data_details_onionreply(result, buffer, datatok,
245+
shared_secrets))
169246
goto fail;
170-
171-
if (rawmsgtok != NULL)
172-
result->raw_message =
173-
json_tok_bin_from_hex(result, buffer, rawmsgtok);
174-
else
175-
result->raw_message = NULL;
176-
177-
if (failcodenametok != NULL)
178-
result->failcodename =
179-
json_strdup(result, buffer, failcodenametok);
180-
else
181-
result->failcodename = NULL;
182-
183-
if(failcodetok){
184-
result->failcode = tal(result, enum onion_wire);
185-
json_to_u32(buffer, failcodetok, result->failcode);
186-
}else
187-
result->failcode = NULL;
188-
if (erridxtok != NULL) {
189-
result->erring_index = tal(result, u32);
190-
json_to_u32(buffer, erridxtok, result->erring_index);
191-
} else {
192-
result->erring_index = NULL;
193-
}
194-
195-
if (errdirtok != NULL) {
196-
result->erring_direction = tal(result, int);
197-
json_to_int(buffer, errdirtok,
198-
result->erring_direction);
199-
} else {
200-
result->erring_direction = NULL;
201-
}
202-
203-
if (errnodetok != NULL) {
204-
result->erring_node = tal(result, struct node_id);
205-
json_to_node_id(buffer, errnodetok,
206-
result->erring_node);
207-
} else {
208-
result->erring_node = NULL;
209-
}
210-
211-
if (errchantok != NULL) {
212-
result->erring_channel =
213-
tal(result, struct short_channel_id);
214-
json_to_short_channel_id(buffer, errchantok,
215-
result->erring_channel);
216-
} else {
217-
result->erring_channel = NULL;
218-
}
219247
}
220-
221248
return result;
222249
fail:
223250
return tal_free(result);

plugins/renepay/json.h

+2-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,8 @@ struct route *tal_route_from_json(const tal_t *ctx, const char *buf,
1313

1414
struct payment_result *tal_sendpay_result_from_json(const tal_t *ctx,
1515
const char *buffer,
16-
const jsmntok_t *toks);
16+
const jsmntok_t *toks,
17+
struct secret *shared_secrets);
1718

1819
void json_add_payment(struct json_stream *s, const struct payment *payment);
1920

plugins/renepay/routetracker.c

+16-9
Original file line numberDiff line numberDiff line change
@@ -209,14 +209,19 @@ static struct command_result *sendpay_done(struct command *cmd,
209209

210210
const jsmntok_t *secretstok =
211211
json_get_member(buf, result, "shared_secrets");
212-
assert(secretstok->type == JSMN_ARRAY);
213212

214-
route->shared_secrets = tal_arr(route, struct secret, secretstok->size);
215-
json_for_each_arr(i, t, secretstok)
216-
{
217-
ret = json_to_secret(buf, t, &route->shared_secrets[i]);
218-
assert(ret);
219-
}
213+
if (secretstok) {
214+
assert(secretstok->type == JSMN_ARRAY);
215+
216+
route->shared_secrets =
217+
tal_arr(route, struct secret, secretstok->size);
218+
json_for_each_arr(i, t, secretstok)
219+
{
220+
ret = json_to_secret(buf, t, &route->shared_secrets[i]);
221+
assert(ret);
222+
}
223+
} else
224+
route->shared_secrets = NULL;
220225
return command_still_pending(cmd);
221226
}
222227

@@ -440,7 +445,8 @@ struct command_result *notification_sendpay_failure(struct command *cmd,
440445
}
441446

442447
assert(route->result == NULL);
443-
route->result = tal_sendpay_result_from_json(route, buf, sub);
448+
route->result = tal_sendpay_result_from_json(route, buf, sub,
449+
route->shared_secrets);
444450
if (route->result == NULL)
445451
plugin_err(pay_plugin->plugin,
446452
"Unable to parse sendpay_failure: %.*s",
@@ -504,7 +510,8 @@ struct command_result *notification_sendpay_success(struct command *cmd,
504510
}
505511

506512
assert(route->result == NULL);
507-
route->result = tal_sendpay_result_from_json(route, buf, sub);
513+
route->result = tal_sendpay_result_from_json(route, buf, sub,
514+
route->shared_secrets);
508515
if (route->result == NULL)
509516
plugin_err(pay_plugin->plugin,
510517
"Unable to parse sendpay_success: %.*s",

plugins/renepay/sendpay.c

+42-2
Original file line numberDiff line numberDiff line change
@@ -342,6 +342,46 @@ static struct command_result *renesendpay_done(struct command *cmd,
342342
return command_finished(cmd, response);
343343
}
344344

345+
static struct command_result *renesendpay_finished(struct command *cmd,
346+
struct renesendpay *renesendpay)
347+
{
348+
struct json_stream *response = jsonrpc_stream_success(cmd);
349+
json_add_string(response, "message",
350+
"Monitor status with listpays or waitsendpay");
351+
json_add_sha256(response, "payment_hash", &renesendpay->payment_hash);
352+
json_add_u64(response, "groupid", renesendpay->groupid);
353+
json_add_u64(response, "partid", renesendpay->partid);
354+
json_add_node_id(response, "destination", &renesendpay->destination);
355+
json_add_amount_msat(response, "amount_sent_msat",
356+
renesendpay->sent_amount);
357+
json_add_amount_msat(response, "amount_delivered_msat",
358+
renesendpay->deliver_amount);
359+
json_add_amount_msat(response, "amount_total_msat",
360+
renesendpay->total_amount);
361+
json_add_string(response, "invoice", renesendpay->invoice);
362+
json_add_string(response, "status", "pending");
363+
364+
if (renesendpay->label)
365+
json_add_string(response, "label", renesendpay->label);
366+
if (renesendpay->description)
367+
json_add_string(response, "description",
368+
renesendpay->description);
369+
if (renesendpay->metadata)
370+
json_add_hex_talarr(response, "payment_metadata",
371+
renesendpay->metadata);
372+
373+
if (renesendpay->shared_secrets) {
374+
json_array_start(response, "shared_secrets");
375+
for (size_t i = 0; i < tal_count(renesendpay->shared_secrets);
376+
i++) {
377+
json_add_secret(response, NULL,
378+
&renesendpay->shared_secrets[i]);
379+
}
380+
json_array_end(response);
381+
}
382+
return command_finished(cmd, response);
383+
}
384+
345385
static u32 initial_cltv_delta(const struct renesendpay *renesendpay)
346386
{
347387
if (tal_count(renesendpay->route) == 0)
@@ -439,8 +479,8 @@ static struct command_result *waitblockheight_done(struct command *cmd,
439479
initial_cltv_delta(renesendpay) +
440480
renesendpay->blockheight);
441481
}
442-
443-
return send_outreq(req);
482+
send_outreq(req);
483+
return renesendpay_finished(cmd, renesendpay);
444484
}
445485

446486
struct command_result *json_renesendpay(struct command *cmd,

0 commit comments

Comments
 (0)