From 44972b2e154e14ee9bd3667d956958ab84da9ad9 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Fri, 16 May 2025 21:34:23 +0930 Subject: [PATCH] chanbackup: unbias our random peer selection. We picked one node and iterated. This means we would only sent to 1, not 2 nodes if we picked the last (common if there were only a few peers). But it also means we would generally send to the same pair of nodes, which isn't great for redundancy. Rework to be more random. Signed-off-by: Rusty Russell --- plugins/chanbackup.c | 52 ++++++++++++++++++++++++++++++++++---------- 1 file changed, 40 insertions(+), 12 deletions(-) diff --git a/plugins/chanbackup.c b/plugins/chanbackup.c index 9f0b3bf2b..1fb660a3f 100644 --- a/plugins/chanbackup.c +++ b/plugins/chanbackup.c @@ -551,13 +551,47 @@ static struct command_result *after_send_scb_single_fail(struct command *cmd, return notification_or_hook_done(cmd); } +static bool already_have_node_id(const struct node_id *ids, + const struct node_id *id) +{ + for (size_t i = 0; i < tal_count(ids); i++) + if (node_id_eq(&ids[i], id)) + return true; + + return false; +} + +static const struct node_id *random_peers(const tal_t *ctx, + const struct chanbackup *cb) +{ + struct peer_map_iter it; + const struct node_id *peer; + struct node_id *ids = tal_arr(ctx, struct node_id, 0); + + /* Simple case: pick all of them */ + if (peer_map_count(cb->peers) <= NUM_BACKUP_PEERS) { + for (peer = peer_map_first(cb->peers, &it); + peer; + peer = peer_map_next(cb->peers, &it)) { + tal_arr_expand(&ids, *peer); + } + } else { + while (peer_map_count(cb->peers) < NUM_BACKUP_PEERS) { + peer = peer_map_pick(cb->peers, pseudorand_u64(), &it); + if (already_have_node_id(ids, peer)) + continue; + tal_arr_expand(&ids, *peer); + } + } + return ids; +} + static struct command_result *send_to_peers(struct command *cmd) { struct out_req *req; size_t *idx = tal(cmd, size_t); u8 *serialise_scb, *data; - struct peer_map_iter it; - const struct node_id *peer; + const struct node_id *peers; struct chanbackup *cb = chanbackup(cmd->plugin); if (!cb->send_our_peer_backup) @@ -582,14 +616,13 @@ static struct command_result *send_to_peers(struct command *cmd) } serialise_scb = towire_peer_storage(cmd, data); - *idx = 0; - for (peer = peer_map_pick(cb->peers, pseudorand_u64(), &it); - peer; - peer = peer_map_next(cb->peers, &it)) { + peers = random_peers(tmpctx, cb); + *idx = tal_count(peers); + for (size_t i = 0; i < tal_count(peers); i++) { struct info *info = tal(cmd, struct info); info->idx = idx; - info->node_id = *peer; + info->node_id = peers[i]; req = jsonrpc_request_start(cmd, "sendcustommsg", @@ -599,12 +632,7 @@ static struct command_result *send_to_peers(struct command *cmd) json_add_node_id(req->js, "node_id", &info->node_id); json_add_hex_talarr(req->js, "msg", serialise_scb); - (*info->idx)++; send_outreq(req); - - /* Only send to NUM_BACKUP_PEERS for each update */ - if (*info->idx == NUM_BACKUP_PEERS) - break; } if (*idx == 0)