Skip to content

Commit 2264b93

Browse files
nepetrustyrussell
authored andcommitted
lightningd: Add extra_tlvs to htlc_accepted_hook
Add serializing and deserializing of the extra tlvs to to the htlc_accepted_hook to allow plugin users to replace the tlv stream that is attached to the update_add_htlc message on forwards. Signed-off-by: Peter Neuroth <[email protected]>
1 parent ef52de8 commit 2264b93

File tree

7 files changed

+147
-11
lines changed

7 files changed

+147
-11
lines changed

lightningd/htlc_end.c

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
#include <common/pseudorand.h>
77
#include <lightningd/htlc_end.h>
88
#include <lightningd/log.h>
9+
#include <wire/tlvstream.h>
910

1011
size_t hash_htlc_key(const struct htlc_key *k)
1112
{
@@ -130,6 +131,7 @@ struct htlc_in *new_htlc_in(const tal_t *ctx,
130131
const struct secret *shared_secret TAKES,
131132
const struct pubkey *path_key TAKES,
132133
const u8 *onion_routing_packet,
134+
const struct tlv_field *extra_tlvs,
133135
bool fail_immediate)
134136
{
135137
struct htlc_in *hin = tal(ctx, struct htlc_in);
@@ -146,6 +148,15 @@ struct htlc_in *new_htlc_in(const tal_t *ctx,
146148
hin->path_key = tal_dup_or_null(hin, struct pubkey, path_key);
147149
memcpy(hin->onion_routing_packet, onion_routing_packet,
148150
sizeof(hin->onion_routing_packet));
151+
if (extra_tlvs) {
152+
hin->extra_tlvs = tal_dup_talarr(hin, struct tlv_field, extra_tlvs);
153+
for (size_t i = 0; i < tal_count(extra_tlvs); i++) {
154+
/* We need to attach the value to the correct parent */
155+
hin->extra_tlvs[i].value = tal_dup_talarr(hin, u8, hin->extra_tlvs[i].value);
156+
}
157+
} else {
158+
hin->extra_tlvs = NULL;
159+
}
149160

150161
hin->hstate = RCVD_ADD_COMMIT;
151162
hin->badonion = 0;
@@ -265,6 +276,7 @@ struct htlc_out *new_htlc_out(const tal_t *ctx,
265276
const struct sha256 *payment_hash,
266277
const u8 *onion_routing_packet,
267278
const struct pubkey *path_key,
279+
const struct tlv_field* extra_tlvs,
268280
bool am_origin,
269281
struct amount_msat final_msat,
270282
u64 partid,
@@ -291,6 +303,17 @@ struct htlc_out *new_htlc_out(const tal_t *ctx,
291303
hout->timeout = NULL;
292304

293305
hout->path_key = tal_dup_or_null(hout, struct pubkey, path_key);
306+
307+
if (extra_tlvs) {
308+
hout->extra_tlvs = tal_dup_talarr(hout, struct tlv_field, extra_tlvs);
309+
for (size_t i = 0; i < tal_count(extra_tlvs); i++) {
310+
/* We need to attach the value to the correct parent */
311+
hout->extra_tlvs[i].value = tal_dup_talarr(hout, u8, hout->extra_tlvs[i].value);
312+
}
313+
} else {
314+
hout->extra_tlvs = NULL;
315+
}
316+
294317
hout->am_origin = am_origin;
295318
if (am_origin) {
296319
hout->partid = partid;

lightningd/htlc_end.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,9 @@ struct htlc_in {
5858

5959
/* The decoded onion payload after hooks processed it. */
6060
struct onion_payload *payload;
61+
62+
/* Incommimg extra update_add_htlc_tlv tlvs */
63+
struct tlv_field *extra_tlvs;
6164
};
6265

6366
struct htlc_out {
@@ -106,6 +109,9 @@ struct htlc_out {
106109

107110
/* Timer we use in case they don't add an HTLC in a timely manner. */
108111
struct oneshot *timeout;
112+
113+
/* Extra tlvs that are extended to the update_add_htlc_tlvs */
114+
struct tlv_field *extra_tlvs;
109115
};
110116

111117
static inline const struct htlc_key *keyof_htlc_in(const struct htlc_in *in)
@@ -158,6 +164,7 @@ struct htlc_in *new_htlc_in(const tal_t *ctx,
158164
const struct secret *shared_secret TAKES,
159165
const struct pubkey *path_key TAKES,
160166
const u8 *onion_routing_packet,
167+
const struct tlv_field *extra_tlvs TAKES,
161168
bool fail_immediate);
162169

163170
/* You need to set the ID, then connect_htlc_out this! */
@@ -168,6 +175,7 @@ struct htlc_out *new_htlc_out(const tal_t *ctx,
168175
const struct sha256 *payment_hash,
169176
const u8 *onion_routing_packet,
170177
const struct pubkey *path_key,
178+
const struct tlv_field *extra_tlvs,
171179
bool am_origin,
172180
struct amount_msat final_msat,
173181
u64 partid,

lightningd/pay.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -783,8 +783,8 @@ static const u8 *send_onion(const tal_t *ctx, struct lightningd *ld,
783783
return send_htlc_out(ctx, channel, first_hop->amount,
784784
base_expiry + first_hop->delay,
785785
final_amount, payment_hash,
786-
path_key, partid, groupid, onion, NULL, hout);
787-
}
786+
path_key, NULL, partid, groupid, onion, NULL, hout);
787+
}
788788

789789
static struct command_result *check_invoice_request_usage(struct command *cmd,
790790
const struct sha256 *local_invreq_id)
@@ -2093,7 +2093,7 @@ static struct command_result *json_injectpaymentonion(struct command *cmd,
20932093
failmsg = send_htlc_out(tmpctx, next, *msat,
20942094
*cltv, *destination_msat,
20952095
payment_hash,
2096-
next_path_key, *partid, *groupid,
2096+
next_path_key, NULL, *partid, *groupid,
20972097
serialize_onionpacket(tmpctx, rs->next),
20982098
NULL, &hout);
20992099
if (failmsg) {

lightningd/peer_htlcs.c

Lines changed: 94 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
#include <ccan/mem/mem.h>
44
#include <ccan/tal/str/str.h>
55
#include <channeld/channeld_wiregen.h>
6+
#include <common/bigsize.h>
67
#include <common/blinding.h>
78
#include <common/configdir.h>
89
#include <common/ecdh.h>
@@ -23,6 +24,10 @@
2324
#include <lightningd/plugin_hook.h>
2425
#include <lightningd/subd.h>
2526
#include <onchaind/onchaind_wiregen.h>
27+
#include <stdio.h>
28+
#include <wire/onion_wiregen.h>
29+
#include <wire/peer_wiregen.h>
30+
#include <wire/tlvstream.h>
2631

2732
#ifndef SUPERVERBOSE
2833
#define SUPERVERBOSE(...)
@@ -695,6 +700,7 @@ const u8 *send_htlc_out(const tal_t *ctx,
695700
struct amount_msat final_msat,
696701
const struct sha256 *payment_hash,
697702
const struct pubkey *path_key,
703+
const struct tlv_field *extra_tlvs,
698704
u64 partid,
699705
u64 groupid,
700706
const u8 *onion_routing_packet,
@@ -729,7 +735,8 @@ const u8 *send_htlc_out(const tal_t *ctx,
729735
/* Make peer's daemon own it, catch if it dies. */
730736
*houtp = new_htlc_out(out->owner, out, amount, cltv,
731737
payment_hash, onion_routing_packet,
732-
path_key, in == NULL,
738+
path_key, extra_tlvs,
739+
in == NULL,
733740
final_msat,
734741
partid, groupid, in);
735742
tal_add_destructor(*houtp, destroy_hout_subd_died);
@@ -742,6 +749,13 @@ const u8 *send_htlc_out(const tal_t *ctx,
742749
*houtp);
743750
}
744751

752+
if (extra_tlvs) {
753+
raw_tlvs = tal_arr(tmpctx, u8, 0);
754+
towire_tlvstream_raw(&raw_tlvs,
755+
tal_dup_talarr(tmpctx, struct tlv_field,
756+
extra_tlvs));
757+
}
758+
745759
msg = towire_channeld_offer_htlc(out, amount, cltv, payment_hash,
746760
onion_routing_packet, path_key,
747761
raw_tlvs);
@@ -797,7 +811,8 @@ static void forward_htlc(struct htlc_in *hin,
797811
const struct short_channel_id *forward_scid,
798812
const struct channel_id *forward_to,
799813
const u8 next_onion[TOTAL_PACKET_SIZE(ROUTING_INFO_SIZE)],
800-
const struct pubkey *next_path_key)
814+
const struct pubkey *next_path_key,
815+
const struct tlv_field *extra_tlvs)
801816
{
802817
const u8 *failmsg;
803818
struct lightningd *ld = hin->key.channel->peer->ld;
@@ -912,7 +927,7 @@ static void forward_htlc(struct htlc_in *hin,
912927
failmsg = send_htlc_out(tmpctx, next, amt_to_forward,
913928
outgoing_cltv_value, AMOUNT_MSAT(0),
914929
&hin->payment_hash,
915-
next_path_key, 0 /* partid */, 0 /* groupid */,
930+
next_path_key, extra_tlvs, 0 /* partid */, 0 /* groupid */,
916931
next_onion, hin, &hout);
917932
if (!failmsg)
918933
return;
@@ -942,6 +957,7 @@ struct htlc_accepted_hook_payload {
942957
u64 failtlvtype;
943958
size_t failtlvpos;
944959
const char *failexplanation;
960+
u8 *extra_tlvs_raw;
945961
};
946962

947963
static void
@@ -998,8 +1014,8 @@ static bool htlc_accepted_hook_deserialize(struct htlc_accepted_hook_payload *re
9981014
struct htlc_in *hin = request->hin;
9991015
struct lightningd *ld = request->ld;
10001016
struct preimage payment_preimage;
1001-
const jsmntok_t *resulttok, *paykeytok, *payloadtok, *fwdtok;
1002-
u8 *failonion;
1017+
const jsmntok_t *resulttok, *paykeytok, *payloadtok, *fwdtok, *extra_tlvs_tok;
1018+
u8 *failonion, *raw_tlvs;
10031019

10041020
if (!toks || !buffer)
10051021
return true;
@@ -1013,6 +1029,49 @@ static bool htlc_accepted_hook_deserialize(struct htlc_accepted_hook_payload *re
10131029
json_strdup(tmpctx, buffer, toks));
10141030
}
10151031

1032+
extra_tlvs_tok = json_get_member(buffer, toks, "extra_tlvs");
1033+
if (extra_tlvs_tok) {
1034+
size_t max;
1035+
struct tlv_update_add_htlc_tlvs *check_extra_tlvs;
1036+
1037+
raw_tlvs = json_tok_bin_from_hex(tmpctx, buffer,
1038+
extra_tlvs_tok);
1039+
if (!raw_tlvs)
1040+
fatal("Bad custom tlvs for htlc_accepted"
1041+
" hook: %.*s",
1042+
extra_tlvs_tok->end - extra_tlvs_tok->start,
1043+
buffer + extra_tlvs_tok->start);
1044+
1045+
max = tal_bytelen(raw_tlvs);
1046+
1047+
/* We check if the custom tlvs are still valid BOLT#1 tlvs.
1048+
* As these are appended to forwarded htlcs we check for valid
1049+
* update_add_htlc_tlvs (restricts to known even types).
1050+
* NOTE: We may be less strict and allow unknown evens .*/
1051+
const u8 *cursor = raw_tlvs;
1052+
check_extra_tlvs = fromwire_tlv_update_add_htlc_tlvs(tmpctx,
1053+
&cursor,
1054+
&max);
1055+
if (!check_extra_tlvs) {
1056+
fatal("htlc_accepted_hook returned bad extra_tlvs %s",
1057+
tal_hex(tmpctx, raw_tlvs));
1058+
}
1059+
1060+
/* If we got a blinded path key we replace the next path key
1061+
* with it. */
1062+
if (check_extra_tlvs->blinded_path) {
1063+
tal_free(request->next_path_key);
1064+
request->next_path_key
1065+
= tal_steal(request,
1066+
check_extra_tlvs->blinded_path);
1067+
}
1068+
1069+
/* We made it and got a valid extra_tlvs: Replace the current
1070+
* extra_tlvs with it. */
1071+
tal_free(request->extra_tlvs_raw);
1072+
request->extra_tlvs_raw = tal_steal(request, raw_tlvs);
1073+
}
1074+
10161075
payloadtok = json_get_member(buffer, toks, "payload");
10171076
if (payloadtok) {
10181077
u8 *payload = json_tok_bin_from_hex(rs, buffer, payloadtok);
@@ -1170,6 +1229,9 @@ static void htlc_accepted_hook_serialize(struct htlc_accepted_hook_payload *p,
11701229
json_add_u32(s, "cltv_expiry", expiry);
11711230
json_add_s32(s, "cltv_expiry_relative", expiry - blockheight);
11721231
json_add_sha256(s, "payment_hash", &hin->payment_hash);
1232+
if (p->extra_tlvs_raw) {
1233+
json_add_hex_talarr(s, "extra_tlvs", p->extra_tlvs_raw);
1234+
}
11731235
json_object_end(s);
11741236
}
11751237

@@ -1200,13 +1262,25 @@ htlc_accepted_hook_final(struct htlc_accepted_hook_payload *request STEALS)
12001262
NULL, request->failtlvtype,
12011263
request->failtlvpos)));
12021264
} else if (rs->nextcase == ONION_FORWARD) {
1265+
struct tlv_field *extra_tlvs;
1266+
1267+
if (request->extra_tlvs_raw) {
1268+
const u8 *cursor = request->extra_tlvs_raw;
1269+
size_t max = tal_bytelen(cursor);
1270+
extra_tlvs = tal_arr(request, struct tlv_field, 0);
1271+
fromwire_tlv(&cursor, &max, NULL, 0, request,
1272+
&extra_tlvs, NULL, NULL, NULL);
1273+
} else {
1274+
extra_tlvs = NULL;
1275+
}
1276+
12031277
forward_htlc(hin, hin->cltv_expiry,
12041278
request->payload->amt_to_forward,
12051279
request->payload->outgoing_cltv,
12061280
request->payload->forward_channel,
12071281
request->fwd_channel_id,
12081282
serialize_onionpacket(tmpctx, rs->next),
1209-
request->next_path_key);
1283+
request->next_path_key, extra_tlvs);
12101284
} else
12111285
handle_localpay(hin,
12121286
request->payload->amt_to_forward,
@@ -1484,6 +1558,14 @@ static bool peer_accepted_htlc(const tal_t *ctx,
14841558
hook_payload->fwd_channel_id
14851559
= calc_forwarding_channel(ld, hook_payload);
14861560

1561+
if(hin->extra_tlvs) {
1562+
hook_payload->extra_tlvs_raw = tal_arr(hook_payload, u8, 0);
1563+
towire_tlvstream_raw(&hook_payload->extra_tlvs_raw,
1564+
hin->extra_tlvs);
1565+
} else {
1566+
hook_payload->extra_tlvs_raw = NULL;
1567+
}
1568+
14871569
plugin_hook_call_htlc_accepted(ld, NULL, hook_payload);
14881570

14891571
/* Falling through here is ok, after all the HTLC locked */
@@ -2210,6 +2292,7 @@ static bool channel_added_their_htlc(struct channel *channel,
22102292
op ? &shared_secret : NULL,
22112293
added->path_key,
22122294
added->onion_routing_packet,
2295+
added->extra_tlvs,
22132296
added->fail_immediate);
22142297

22152298
/* Save an incoming htlc to the wallet */
@@ -2641,13 +2724,15 @@ const struct existing_htlc **peer_htlcs(const tal_t *ctx,
26412724
else
26422725
f = NULL;
26432726

2727+
26442728
existing = new_existing_htlc(htlcs, hin->key.id, hin->hstate,
26452729
hin->msat, &hin->payment_hash,
26462730
hin->cltv_expiry,
26472731
hin->onion_routing_packet,
26482732
hin->path_key,
26492733
hin->preimage,
2650-
f, NULL);
2734+
f,
2735+
hin->extra_tlvs);
26512736
tal_arr_expand(&htlcs, existing);
26522737
}
26532738

@@ -2679,7 +2764,8 @@ const struct existing_htlc **peer_htlcs(const tal_t *ctx,
26792764
hout->onion_routing_packet,
26802765
hout->path_key,
26812766
hout->preimage,
2682-
f, NULL);
2767+
f,
2768+
hout->extra_tlvs);
26832769
tal_arr_expand(&htlcs, existing);
26842770
}
26852771

lightningd/peer_htlcs.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ const u8 *send_htlc_out(const tal_t *ctx,
3333
struct amount_msat final_msat,
3434
const struct sha256 *payment_hash,
3535
const struct pubkey *path_key,
36+
const struct tlv_field *extra_tlvs,
3637
u64 partid,
3738
u64 groupid,
3839
const u8 *onion_routing_packet,

wallet/test/run-wallet.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -365,6 +365,10 @@ bool fromwire_onchaind_dev_memleak_reply(const void *p UNNEEDED, bool *leak UNNE
365365
/* Generated stub for fromwire_openingd_dev_memleak_reply */
366366
bool fromwire_openingd_dev_memleak_reply(const void *p UNNEEDED, bool *leak UNNEEDED)
367367
{ fprintf(stderr, "fromwire_openingd_dev_memleak_reply called!\n"); abort(); }
368+
/* Generated stub for fromwire_tlv_update_add_htlc_tlvs */
369+
struct tlv_update_add_htlc_tlvs *fromwire_tlv_update_add_htlc_tlvs(const tal_t *ctx UNNEEDED,
370+
const u8 **cursor UNNEEDED, size_t *max UNNEEDED)
371+
{ fprintf(stderr, "fromwire_tlv_update_add_htlc_tlvs called!\n"); abort(); }
368372
/* Generated stub for get_network_blockheight */
369373
u32 get_network_blockheight(const struct chain_topology *topo UNNEEDED)
370374
{ fprintf(stderr, "get_network_blockheight called!\n"); abort(); }

wallet/wallet.c

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3415,6 +3415,13 @@ static bool wallet_stmt2htlc_in(struct channel *channel,
34153415
/* FIXME: save path_key in db !*/
34163416
in->path_key = NULL;
34173417
in->payload = NULL;
3418+
/* FIXME: save extra_tlvs in db! But: check the implications that a
3419+
* spammy peer - giving us big extra tlvs - would have on our database.
3420+
* Right now, not saving the extra tlvs in the db seems OK as it is
3421+
* only relevant in the case that I forward but restart in the middle
3422+
* of a payment.
3423+
*/
3424+
in->extra_tlvs = NULL;
34183425

34193426
db_col_sha256(stmt, "payment_hash", &in->payment_hash);
34203427

@@ -3487,6 +3494,13 @@ static bool wallet_stmt2htlc_out(struct wallet *wallet,
34873494
db_col_sha256(stmt, "payment_hash", &out->payment_hash);
34883495
/* FIXME: save path_key in db !*/
34893496
out->path_key = NULL;
3497+
/* FIXME: save extra_tlvs in db! But: check the implications that a
3498+
* spammy peer - giving us big extra tlvs - would have on our database.
3499+
* Right now, not saving the extra tlvs in the db seems OK as it is
3500+
* only relevant in the case that I forward but restart in the middle
3501+
* of a payment.
3502+
*/
3503+
out->extra_tlvs = NULL;
34903504

34913505
out->preimage = db_col_optional(out, stmt, "payment_key", preimage);
34923506

0 commit comments

Comments
 (0)