Skip to content

Commit 66dcba0

Browse files
committed
gossipd: hand raw pubkeys in getnodes and getchannels entries.
We spend quite a bit of time in libsecp256k1 moving them to and from DER encoding. With a bit of care, we can transfer the raw bytes from gossipd and manually decode them so a malformed one can't make us abort(). Before: real 0m0.629000-0.695000(0.64985+/-0.019)s After: real 0m0.359000-0.433000(0.37645+/-0.023)s At this point, the main issues are 11% of time spent in ccan/io's backend_wake (I tried using a hash table there, but that actually makes the small-number-of-fds case slower), and 65% of gossipd's time is in marshalling the response (all those tal_resize add up!). Signed-off-by: Rusty Russell <[email protected]>
1 parent c403415 commit 66dcba0

File tree

4 files changed

+40
-15
lines changed

4 files changed

+40
-15
lines changed

gossipd/gossipd.c

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1370,6 +1370,11 @@ static struct io_plan *getroute_req(struct io_conn *conn, struct daemon *daemon,
13701370
return daemon_conn_read_next(conn, &daemon->master);
13711371
}
13721372

1373+
#define raw_pubkey(arr, id) \
1374+
do { BUILD_ASSERT(sizeof(arr) == sizeof(*id)); \
1375+
memcpy(arr, id, sizeof(*id)); \
1376+
} while(0)
1377+
13731378
static void append_half_channel(struct gossip_getchannels_entry **entries,
13741379
const struct chan *chan,
13751380
int idx)
@@ -1382,8 +1387,8 @@ static void append_half_channel(struct gossip_getchannels_entry **entries,
13821387

13831388
e = tal_arr_expand(entries);
13841389

1385-
e->source = chan->nodes[idx]->id;
1386-
e->destination = chan->nodes[!idx]->id;
1390+
raw_pubkey(e->source, &chan->nodes[idx]->id);
1391+
raw_pubkey(e->destination, &chan->nodes[!idx]->id);
13871392
e->satoshis = chan->satoshis;
13881393
e->channel_flags = c->channel_flags;
13891394
e->message_flags = c->message_flags;
@@ -1442,7 +1447,7 @@ static void append_node(const struct gossip_getnodes_entry ***entries,
14421447

14431448
*tal_arr_expand(entries) = e
14441449
= tal(*entries, struct gossip_getnodes_entry);
1445-
e->nodeid = n->id;
1450+
raw_pubkey(e->nodeid, &n->id);
14461451
e->last_timestamp = n->last_timestamp;
14471452
if (e->last_timestamp < 0)
14481453
return;

lightningd/gossip_control.c

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,24 @@ void gossipd_notify_spend(struct lightningd *ld,
177177
subd_send_msg(ld->gossip, msg);
178178
}
179179

180+
/* Gossipd shouldn't give us bad pubkeys, but don't abort if they do */
181+
static void json_add_raw_pubkey(struct json_result *response,
182+
const char *fieldname,
183+
const u8 raw_pubkey[sizeof(struct pubkey)])
184+
{
185+
secp256k1_pubkey pubkey;
186+
u8 der[PUBKEY_DER_LEN];
187+
size_t outlen = PUBKEY_DER_LEN;
188+
189+
memcpy(&pubkey, raw_pubkey, sizeof(pubkey));
190+
if (!secp256k1_ec_pubkey_serialize(secp256k1_ctx, der, &outlen,
191+
&pubkey,
192+
SECP256K1_EC_COMPRESSED))
193+
json_add_string(response, fieldname, "INVALID PUBKEY");
194+
else
195+
json_add_hex(response, fieldname, der, sizeof(der));
196+
}
197+
180198
static void json_getnodes_reply(struct subd *gossip UNUSED, const u8 *reply,
181199
const int *fds UNUSED,
182200
struct command *cmd)
@@ -198,7 +216,7 @@ static void json_getnodes_reply(struct subd *gossip UNUSED, const u8 *reply,
198216
struct json_escaped *esc;
199217

200218
json_object_start(response, NULL);
201-
json_add_pubkey(response, "nodeid", &nodes[i]->nodeid);
219+
json_add_raw_pubkey(response, "nodeid", nodes[i]->nodeid);
202220
if (nodes[i]->last_timestamp < 0) {
203221
json_object_end(response);
204222
continue;
@@ -349,9 +367,9 @@ static void json_listchannels_reply(struct subd *gossip UNUSED, const u8 *reply,
349367
json_array_start(response, "channels");
350368
for (i = 0; i < tal_count(entries); i++) {
351369
json_object_start(response, NULL);
352-
json_add_pubkey(response, "source", &entries[i].source);
353-
json_add_pubkey(response, "destination",
354-
&entries[i].destination);
370+
json_add_raw_pubkey(response, "source", entries[i].source);
371+
json_add_raw_pubkey(response, "destination",
372+
entries[i].destination);
355373
json_add_string(response, "short_channel_id",
356374
type_to_string(reply, struct short_channel_id,
357375
&entries[i].short_channel_id));

lightningd/gossip_msg.c

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ struct gossip_getnodes_entry *fromwire_gossip_getnodes_entry(const tal_t *ctx,
1212
u16 flen;
1313

1414
entry = tal(ctx, struct gossip_getnodes_entry);
15-
fromwire_pubkey(pptr, max, &entry->nodeid);
15+
fromwire(pptr, max, entry->nodeid, sizeof(entry->nodeid));
1616

1717
entry->last_timestamp = fromwire_u64(pptr, max);
1818
if (entry->last_timestamp < 0) {
@@ -43,7 +43,7 @@ struct gossip_getnodes_entry *fromwire_gossip_getnodes_entry(const tal_t *ctx,
4343
void towire_gossip_getnodes_entry(u8 **pptr,
4444
const struct gossip_getnodes_entry *entry)
4545
{
46-
towire_pubkey(pptr, &entry->nodeid);
46+
towire(pptr, entry->nodeid, sizeof(entry->nodeid));
4747
towire_u64(pptr, entry->last_timestamp);
4848

4949
if (entry->last_timestamp < 0)
@@ -97,8 +97,8 @@ void fromwire_gossip_getchannels_entry(const u8 **pptr, size_t *max,
9797
struct gossip_getchannels_entry *entry)
9898
{
9999
fromwire_short_channel_id(pptr, max, &entry->short_channel_id);
100-
fromwire_pubkey(pptr, max, &entry->source);
101-
fromwire_pubkey(pptr, max, &entry->destination);
100+
fromwire(pptr, max, entry->source, sizeof(entry->source));
101+
fromwire(pptr, max, entry->destination, sizeof(entry->destination));
102102
entry->satoshis = fromwire_u64(pptr, max);
103103
entry->message_flags = fromwire_u8(pptr, max);
104104
entry->channel_flags = fromwire_u8(pptr, max);
@@ -114,8 +114,8 @@ void towire_gossip_getchannels_entry(u8 **pptr,
114114
const struct gossip_getchannels_entry *entry)
115115
{
116116
towire_short_channel_id(pptr, &entry->short_channel_id);
117-
towire_pubkey(pptr, &entry->source);
118-
towire_pubkey(pptr, &entry->destination);
117+
towire(pptr, entry->source, sizeof(entry->source));
118+
towire(pptr, entry->destination, sizeof(entry->destination));
119119
towire_u64(pptr, entry->satoshis);
120120
towire_u8(pptr, entry->message_flags);
121121
towire_u8(pptr, entry->channel_flags);

lightningd/gossip_msg.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,8 @@ struct peer_features {
1212
};
1313

1414
struct gossip_getnodes_entry {
15-
struct pubkey nodeid;
15+
/* This is raw to optimize marshaling: be careful! */
16+
u8 nodeid[sizeof(struct pubkey)];
1617
s64 last_timestamp; /* -1 means never: following fields ignored */
1718
u8 *globalfeatures;
1819
struct wireaddr *addresses;
@@ -21,7 +22,8 @@ struct gossip_getnodes_entry {
2122
};
2223

2324
struct gossip_getchannels_entry {
24-
struct pubkey source, destination;
25+
/* These are raw to optimize marshaling: be careful! */
26+
u8 source[sizeof(struct pubkey)], destination[sizeof(struct pubkey)];
2527
u64 satoshis;
2628
struct short_channel_id short_channel_id;
2729
u8 message_flags;

0 commit comments

Comments
 (0)