Skip to content

Commit 69bfa6f

Browse files
committed
channeld_fakenet: don't be as brute-force trying to derive keys.
Keep a proper cache of all possible ones. I think this may be the timeout problem: according to the logs, channeld_fakenet stops responding and thus HTLCs eventually time out. ``` ``` 2024-12-16T23:16:16.4874420Z lightningd-1 2024-12-16T22:45:14.068Z UNUSUAL 022d223620a359a47ff7f7ac447c85c46c923da53389221a0054c11c1e3ca31d59-channeld-chan#1: Adding HTLC 18446744073709551615 too slow: killing connection ``` Signed-off-by: Rusty Russell <[email protected]>
1 parent 4b283eb commit 69bfa6f

File tree

1 file changed

+99
-95
lines changed

1 file changed

+99
-95
lines changed

tests/plugins/channeld_fakenet.c

Lines changed: 99 additions & 95 deletions
Original file line numberDiff line numberDiff line change
@@ -41,13 +41,32 @@
4141
#define PEER_FD 3
4242
#define HSM_FD 4
4343

44+
/* Map public keys to the private key */
45+
struct node {
46+
struct privkey p;
47+
struct node_id id;
48+
const char *name;
49+
};
50+
51+
static const struct node_id *node_key(const struct node *n)
52+
{
53+
return &n->id;
54+
}
55+
static bool node_cmp(const struct node *n, const struct node_id *node_id)
56+
{
57+
return node_id_eq(&n->id, node_id);
58+
}
59+
HTABLE_DEFINE_TYPE(struct node, node_key, node_id_hash, node_cmp, node_map);
60+
4461
struct info {
4562
/* To talk to lightningd */
4663
struct daemon_conn *dc;
4764
/* The actual channel (to make sure we can fit!) */
4865
struct channel *channel;
49-
/* Cache of privkeys which have proven useful */
50-
size_t *cached_node_idx;
66+
/* Peer's privkey */
67+
struct node *peer;
68+
/* Fast lookup for node ids to get privkeys */
69+
struct node_map *node_map;
5170
/* Gossip map for lookup up our "channels" */
5271
struct gossmap *gossmap;
5372
/* To check cltv delays */
@@ -72,7 +91,7 @@ struct info {
7291
};
7392

7493
/* FIXME: For the ecdh() function called by onion routines */
75-
static size_t current_nodeidx;
94+
static struct node *current_node;
7695

7796
/* Core of an outgoing HTLC: freed by succeed() or fail() */
7897
struct fake_htlc {
@@ -106,40 +125,6 @@ struct reservation {
106125
struct amount_msat amount;
107126
};
108127

109-
static void make_privkey(size_t idx, struct privkey *pk)
110-
{
111-
/* pyln-testing uses 'lightning-N' then all zeroes as hsm_secret. */
112-
if (idx & 1) {
113-
u32 salt = 0;
114-
struct secret hsm_secret;
115-
memset(&hsm_secret, 0, sizeof(hsm_secret));
116-
snprintf((char *)&hsm_secret, sizeof(hsm_secret),
117-
"lightning-%zu", idx >> 1);
118-
119-
/* This maps hsm_secret -> node privkey */
120-
hkdf_sha256(pk, sizeof(*pk),
121-
&salt, sizeof(salt),
122-
&hsm_secret, sizeof(hsm_secret),
123-
"nodeid", 6);
124-
return;
125-
}
126-
127-
/* gossmap-compress uses the node index (size_t, native endian), then all ones */
128-
memset(pk, 1, sizeof(*pk));
129-
idx >>= 1;
130-
memcpy(pk, &idx, sizeof(idx));
131-
132-
struct pubkey pubkey;
133-
pubkey_from_privkey(pk, &pubkey);
134-
}
135-
136-
static const char *fmt_nodeidx(const tal_t *ctx, size_t idx)
137-
{
138-
if (idx & 1)
139-
return tal_fmt(ctx, "lightningd-%zu", idx >> 1);
140-
return tal_fmt(ctx, "gossmap-node-%zu", idx >> 1);
141-
}
142-
143128
/* Return deterministic value >= min < max for this channel */
144129
static u64 channel_range(const struct info *info,
145130
const struct short_channel_id_dir *scidd,
@@ -150,10 +135,8 @@ static u64 channel_range(const struct info *info,
150135

151136
void ecdh(const struct pubkey *point, struct secret *ss)
152137
{
153-
struct privkey pk;
154-
make_privkey(current_nodeidx, &pk);
155138
if (secp256k1_ecdh(secp256k1_ctx, ss->data, &point->pubkey,
156-
pk.secret.data, NULL, NULL) != 1)
139+
current_node->p.secret.data, NULL, NULL) != 1)
157140
abort();
158141
}
159142

@@ -270,15 +253,65 @@ static u8 *get_next_onion(const tal_t *ctx, const struct route_step *rs)
270253
abort();
271254
}
272255

273-
/* Sets current_nodeidx, *next_onion_packet, *shared_secret and *me, and decodes */
256+
static struct node *make_peer_node(const tal_t *ctx)
257+
{
258+
struct node *n = tal(ctx, struct node);
259+
u32 salt = 0;
260+
struct secret hsm_secret;
261+
struct pubkey pubkey;
262+
263+
memset(&hsm_secret, 0, sizeof(hsm_secret));
264+
snprintf((char *)&hsm_secret, sizeof(hsm_secret),
265+
"lightning-2");
266+
267+
/* This maps hsm_secret -> node privkey */
268+
hkdf_sha256(&n->p, sizeof(n->p),
269+
&salt, sizeof(salt),
270+
&hsm_secret, sizeof(hsm_secret),
271+
"nodeid", 6);
272+
pubkey_from_privkey(&n->p, &pubkey);
273+
node_id_from_pubkey(&n->id, &pubkey);
274+
n->name = tal_fmt(n, "lightningd-2");
275+
276+
return n;
277+
}
278+
279+
/* expected_id is NULL for initial node (aka l2) */
280+
static struct node *get_current_node(struct info *info,
281+
const struct node_id *expected_id)
282+
{
283+
if (!expected_id)
284+
return info->peer;
285+
286+
return node_map_get(info->node_map, expected_id);
287+
}
288+
289+
static void populate_node_map(const struct gossmap *gossmap,
290+
struct node_map *node_map)
291+
{
292+
for (size_t i = 0; i < gossmap_max_node_idx(gossmap); i++) {
293+
struct node *n = tal(node_map, struct node);
294+
struct pubkey pubkey;
295+
296+
/* gossmap-compress uses the node index (size_t, native endian), then all ones */
297+
memset(&n->p, 1, sizeof(n->p));
298+
memcpy(&n->p, &i, sizeof(i));
299+
n->name = tal_fmt(n, "node#%zu", i);
300+
301+
pubkey_from_privkey(&n->p, &pubkey);
302+
node_id_from_pubkey(&n->id, &pubkey);
303+
node_map_add(node_map, n);
304+
}
305+
}
306+
307+
/* Sets current_node, *next_onion_packet, *shared_secret and *me, and decodes */
274308
static struct onion_payload *decode_onion(const tal_t *ctx,
275309
struct info *info,
276310
const u8 onion_routing_packet[],
277311
const struct pubkey *path_key,
278312
const struct sha256 *payment_hash,
279313
struct amount_msat amount,
280314
u32 cltv,
281-
const struct node_id *expected_id,
282315
u8 **next_onion_packet,
283316
struct secret *shared_secret,
284317
struct gossmap_node **me)
@@ -289,9 +322,6 @@ static struct onion_payload *decode_onion(const tal_t *ctx,
289322
struct onion_payload *payload;
290323
u64 failtlvtype;
291324
size_t failtlvpos;
292-
struct privkey pk;
293-
struct pubkey current_pubkey;
294-
struct node_id current_node_id;
295325
const char *explanation;
296326

297327
op = parse_onionpacket(tmpctx, onion_routing_packet,
@@ -301,35 +331,13 @@ static struct onion_payload *decode_onion(const tal_t *ctx,
301331
status_failed(STATUS_FAIL_INTERNAL_ERROR,
302332
"Could not parse onion (failcode %u)", failcode);
303333

304-
/* Try previously-useful keys first */
305-
for (size_t i = 0; i < tal_count(info->cached_node_idx); i++) {
306-
current_nodeidx = info->cached_node_idx[i];
307-
if (!ecdh_maybe_blinding(&op->ephemeralkey, path_key, shared_secret))
308-
abort();
309-
rs = process_onionpacket(tmpctx, op, shared_secret,
310-
payment_hash->u.u8, sizeof(*payment_hash));
311-
if (rs)
312-
break;
313-
}
314-
315-
if (!rs) {
316-
/* Try a new one */
317-
for (current_nodeidx = 0; current_nodeidx < 100000; current_nodeidx++) {
318-
if (!ecdh_maybe_blinding(&op->ephemeralkey, path_key, shared_secret))
319-
abort();
320-
rs = process_onionpacket(tmpctx, op, shared_secret,
321-
payment_hash->u.u8, sizeof(*payment_hash));
322-
if (rs)
323-
break;
324-
}
325-
if (!rs)
326-
status_failed(STATUS_FAIL_INTERNAL_ERROR,
327-
"Could not find privkey for onion");
328-
329-
/* Add to cache */
330-
tal_arr_expand(&info->cached_node_idx, current_nodeidx);
331-
}
332-
334+
if (!ecdh_maybe_blinding(&op->ephemeralkey, path_key, shared_secret))
335+
abort();
336+
rs = process_onionpacket(tmpctx, op, shared_secret,
337+
payment_hash->u.u8, sizeof(*payment_hash));
338+
if (!rs)
339+
status_failed(STATUS_FAIL_INTERNAL_ERROR,
340+
"Could not decode onion for %s", current_node->name);
333341
*next_onion_packet = get_next_onion(ctx, rs);
334342

335343
payload = onion_decode(tmpctx,
@@ -344,26 +352,14 @@ static struct onion_payload *decode_onion(const tal_t *ctx,
344352
}
345353

346354
/* Find ourselves in the gossmap, so we know our channels */
347-
make_privkey(current_nodeidx, &pk);
348-
pubkey_from_privkey(&pk, &current_pubkey);
349-
node_id_from_pubkey(&current_node_id, &current_pubkey);
350-
351-
/* This means pay plugin messed up! */
352-
if (expected_id && !node_id_eq(expected_id, &current_node_id))
353-
status_failed(STATUS_FAIL_INTERNAL_ERROR,
354-
"Onion sent to %s, but encrypted to %s",
355-
fmt_node_id(tmpctx, expected_id),
356-
fmt_node_id(tmpctx, &current_node_id));
357-
358-
*me = gossmap_find_node(info->gossmap, &current_node_id);
355+
*me = gossmap_find_node(info->gossmap, &current_node->id);
359356
if (!*me)
360357
status_failed(STATUS_FAIL_INTERNAL_ERROR,
361358
"Cannot find %s (%s) in gossmap",
362-
fmt_nodeidx(tmpctx, current_nodeidx),
363-
fmt_node_id(tmpctx, &current_node_id));
359+
current_node->name,
360+
fmt_node_id(tmpctx, &current_node->id));
364361

365-
status_debug("Unpacked onion for %s",
366-
fmt_nodeidx(tmpctx, current_nodeidx));
362+
status_debug("Unpacked onion for %s", current_node->name);
367363
return payload;
368364
}
369365

@@ -382,7 +378,7 @@ static void fail(struct info *info,
382378
towire_u16(&msg, failcode);
383379

384380
status_debug("Failing payment at %s due to %s",
385-
fmt_nodeidx(tmpctx, current_nodeidx),
381+
fmt_node_id(tmpctx, &current_node->id),
386382
onion_wire_name(failcode));
387383

388384
err = channel_fail_htlc(info->channel,
@@ -573,8 +569,7 @@ static void add_mpp(struct info *info,
573569
struct preimage preimage;
574570
struct multi_payment *mp;
575571

576-
status_debug("Received payment at %s",
577-
fmt_nodeidx(tmpctx, current_nodeidx));
572+
status_debug("Received payment at %s", current_node->name);
578573
mp = add_payment_part(info, htlc, payload);
579574
if (!mp)
580575
return;
@@ -706,14 +701,20 @@ static void forward_htlc(struct info *info,
706701
struct delayed_forward *dfwd;
707702
unsigned int msec_delay;
708703

704+
current_node = get_current_node(info, expected);
705+
if (!current_node) {
706+
status_failed(STATUS_FAIL_INTERNAL_ERROR,
707+
"Could not find privkey for %s",
708+
fmt_node_id(tmpctx, expected));
709+
}
710+
709711
/* Decode, and figure out who I am */
710712
payload = decode_onion(tmpctx,
711713
info,
712714
onion_routing_packet,
713715
path_key,
714716
&htlc->payment_hash,
715717
amount, cltv_expiry,
716-
expected,
717718
&next_onion_packet,
718719
&shared_secret,
719720
&me);
@@ -1291,7 +1292,10 @@ int main(int argc, char *argv[])
12911292
status_failed(STATUS_FAIL_INTERNAL_ERROR,
12921293
"Loading gossmap %s", strerror(errno));
12931294

1294-
info->cached_node_idx = tal_arr(info, size_t, 0);
1295+
info->node_map = tal(info, struct node_map);
1296+
node_map_init(info->node_map);
1297+
populate_node_map(info->gossmap, info->node_map);
1298+
info->peer = make_peer_node(info);
12951299
info->multi_payments = tal_arr(info, struct multi_payment *, 0);
12961300
info->reservations = tal_arr(info, struct reservation *, 0);
12971301
timers_init(&info->timers, time_mono());

0 commit comments

Comments
 (0)