From d646308a83bce7fd4fb68523186891c835355cda Mon Sep 17 00:00:00 2001 From: Alex Myers Date: Mon, 4 Nov 2024 13:22:21 -0600 Subject: [PATCH] gossipd: seeker: select random peer and tell lightningd This does not validate a node announcement and address, but it does select a node at random from the gossmap and asks lightningd to attempt a connection to it. --- gossipd/seeker.c | 78 ++++++++++++++++++++++++++--- gossipd/test/run-next_block_range.c | 19 +++++++ lightningd/gossip_control.c | 18 +++++-- 3 files changed, 103 insertions(+), 12 deletions(-) diff --git a/gossipd/seeker.c b/gossipd/seeker.c index 6a6fb557e50c..82ef60d82d2c 100644 --- a/gossipd/seeker.c +++ b/gossipd/seeker.c @@ -5,6 +5,7 @@ #include #include #include +#include #include #include #include @@ -13,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -963,18 +965,81 @@ static bool seek_any_unknown_nodes(struct seeker *seeker) return true; } +struct node_and_addrs { + struct node_id *id; + struct wireaddr *addrs; +}; + +/* Find a random node with an address in the announcement. */ +static struct node_and_addrs *get_random_node(const tal_t *ctx, + struct seeker *seeker) +{ + struct gossmap *gossmap = gossmap_manage_get_gossmap(seeker->daemon->gm); + if (gossmap_num_nodes(gossmap) < 1) + return NULL; + u32 max_idx = gossmap_max_node_idx(gossmap); + if (max_idx < 1) + return NULL; + + struct gossmap_node *random_node; + struct node_and_addrs *found_node = NULL; + for (int i = 0; i<20; i++) { + u32 random = pseudorand(max_idx); + random_node = gossmap_node_byidx(gossmap, random); + if (!random_node) { + continue; + } + found_node = tal(ctx, struct node_and_addrs); + found_node->id = tal(found_node, struct node_id); + gossmap_node_get_id(gossmap, random_node, found_node->id); + if (node_id_eq(found_node->id, &seeker->daemon->id)) { + found_node = tal_free(found_node); + continue; + } + found_node->addrs = + gossmap_manage_get_node_addresses(found_node, + seeker->daemon->gm, + found_node->id); + if (!found_node->addrs || tal_count(found_node->addrs) == 0) { + found_node = tal_free(found_node); + continue; + } + + break; + } + + return found_node; + +} + /* Ask lightningd for more peers if we're short on gossip streamers. */ static void maybe_get_new_peer(struct seeker *seeker) { size_t connected_peers = peer_node_id_map_count(seeker->daemon->peers); - if (connected_peers < ARRAY_SIZE(seeker->gossiper)) { - status_debug("seeker: have only %zu connected peers." - " Should connect to more.", - connected_peers); + if (connected_peers >= ARRAY_SIZE(seeker->gossiper)) + return; + + status_debug("seeker: need more peers for gossip (have %zu)", + connected_peers); + + const struct node_and_addrs *random_node; + random_node = get_random_node(tmpctx, seeker); + if (!random_node) { + status_debug("seeker: no more potential peers found"); + return; } - /* TODO: find random node announcement, see if we can connect, - * ask lightningd to connect via towire_gossipd_connect_to_peer. */ + + if(!random_node->id) + status_broken("seeker: random gossip node missing node_id"); + + if(!random_node->addrs || tal_count(random_node->addrs) == 0) + status_broken("seeker: random gossip node missing address"); + + u8 *msg = towire_gossipd_connect_to_peer(NULL, random_node->id, + random_node->addrs); + daemon_conn_send(seeker->daemon->master, take(msg)); + tal_free(random_node); } /* Periodic timer to see how our gossip is going. */ @@ -1001,7 +1066,6 @@ static void seeker_check(struct seeker *seeker) check_probe(seeker, peer_gossip_probe_nannounces); break; case NORMAL: - /* FIXME: maybe_get_more_peers(seeker); */ maybe_get_new_peer(seeker); maybe_rotate_gossipers(seeker); if (!seek_any_unknown_scids(seeker) diff --git a/gossipd/test/run-next_block_range.c b/gossipd/test/run-next_block_range.c index f6197acea888..9de8b17d104f 100644 --- a/gossipd/test/run-next_block_range.c +++ b/gossipd/test/run-next_block_range.c @@ -27,6 +27,9 @@ bool blinding_next_path_privkey(const struct privkey *e UNNEEDED, const struct sha256 *h UNNEEDED, struct privkey *next UNNEEDED) { fprintf(stderr, "blinding_next_path_privkey called!\n"); abort(); } +/* Generated stub for daemon_conn_send */ +void daemon_conn_send(struct daemon_conn *dc UNNEEDED, const u8 *msg UNNEEDED) +{ fprintf(stderr, "daemon_conn_send called!\n"); abort(); } /* Generated stub for find_peer */ struct peer *find_peer(struct daemon *daemon UNNEEDED, const struct node_id *id UNNEEDED) { fprintf(stderr, "find_peer called!\n"); abort(); } @@ -62,12 +65,22 @@ struct gossmap_chan *gossmap_find_chan(const struct gossmap *map UNNEEDED, /* Generated stub for gossmap_manage_get_gossmap */ struct gossmap *gossmap_manage_get_gossmap(struct gossmap_manage *gm UNNEEDED) { fprintf(stderr, "gossmap_manage_get_gossmap called!\n"); abort(); } +/* Generated stub for gossmap_manage_get_node_addresses */ +struct wireaddr *gossmap_manage_get_node_addresses(const tal_t *ctx UNNEEDED, + struct gossmap_manage *gm UNNEEDED, + const struct node_id *node_id UNNEEDED) +{ fprintf(stderr, "gossmap_manage_get_node_addresses called!\n"); abort(); } /* Generated stub for gossmap_max_node_idx */ u32 gossmap_max_node_idx(const struct gossmap *map UNNEEDED) { fprintf(stderr, "gossmap_max_node_idx called!\n"); abort(); } /* Generated stub for gossmap_node_byidx */ struct gossmap_node *gossmap_node_byidx(const struct gossmap *map UNNEEDED, u32 idx UNNEEDED) { fprintf(stderr, "gossmap_node_byidx called!\n"); abort(); } +/* Generated stub for gossmap_node_get_id */ +void gossmap_node_get_id(const struct gossmap *map UNNEEDED, + const struct gossmap_node *node UNNEEDED, + struct node_id *id UNNEEDED) +{ fprintf(stderr, "gossmap_node_get_id called!\n"); abort(); } /* Generated stub for gossmap_nth_chan */ struct gossmap_chan *gossmap_nth_chan(const struct gossmap *map UNNEEDED, const struct gossmap_node *node UNNEEDED, @@ -79,6 +92,9 @@ struct gossmap_node *gossmap_nth_node(const struct gossmap *map UNNEEDED, const struct gossmap_chan *chan UNNEEDED, int n UNNEEDED) { fprintf(stderr, "gossmap_nth_node called!\n"); abort(); } +/* Generated stub for gossmap_num_nodes */ +size_t gossmap_num_nodes(const struct gossmap *map UNNEEDED) +{ fprintf(stderr, "gossmap_num_nodes called!\n"); abort(); } /* Generated stub for memleak_scan_intmap_ */ void memleak_scan_intmap_(struct htable *memtable UNNEEDED, const struct intmap *m UNNEEDED) { fprintf(stderr, "memleak_scan_intmap_ called!\n"); abort(); } @@ -125,6 +141,9 @@ void status_fmt(enum log_level level UNNEEDED, const char *fmt UNNEEDED, ...) { fprintf(stderr, "status_fmt called!\n"); abort(); } +/* Generated stub for towire_gossipd_connect_to_peer */ +u8 *towire_gossipd_connect_to_peer(const tal_t *ctx UNNEEDED, const struct node_id *id UNNEEDED, const struct wireaddr *addrs UNNEEDED) +{ fprintf(stderr, "towire_gossipd_connect_to_peer called!\n"); abort(); } /* Generated stub for towire_sciddir_or_pubkey */ void towire_sciddir_or_pubkey(u8 **pptr UNNEEDED, const struct sciddir_or_pubkey *sciddpk UNNEEDED) diff --git a/lightningd/gossip_control.c b/lightningd/gossip_control.c index 7c4b57e10e71..a9eb60d4819d 100644 --- a/lightningd/gossip_control.c +++ b/lightningd/gossip_control.c @@ -172,13 +172,21 @@ static void handle_connect_to_peer(struct subd *gossip, const u8 *msg) { struct node_id *id = tal(tmpctx, struct node_id); struct wireaddr *addrs; - if (!fromwire_gossipd_connect_to_peer(tmpctx, msg, id, &addrs)) + if (!fromwire_gossipd_connect_to_peer(tmpctx, msg, id, &addrs)) { log_broken(gossip->ld->log, "malformed peer connect request" " from gossipd %s", tal_hex(msg, msg)); - else - log_debug(gossip->ld->log, "asked to connect to %s", - fmt_node_id(msg, &id)); - /* TODO: send node_id and address to connectd. */ + return; + } + log_debug(gossip->ld->log, "attempting connection to %s " + "for additional gossip", fmt_node_id(tmpctx, id)); + u8 *connectmsg; + connectmsg = towire_connectd_connect_to_peer(NULL, + id, + addrs, + NULL, //addrhint, + false, //dns_fallback + true); //transient + subd_send_msg(gossip->ld->connectd, take(connectmsg)); } static unsigned gossip_msg(struct subd *gossip, const u8 *msg, const int *fds)