chanbackup: cache available peers.

We already get the connected hook, so in there we can add to a hash
table of suitable peers.  Rather than subscribe to disconnection, we
simply remove the peer if a sendcustommsg fails.

This does make after_send_scb_single() a bit more complex, since it
needs this specific node_id: we use a `struct info` per node and a
pointer to a shared "idx" reference counter.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
This commit is contained in:
Rusty Russell
2025-05-16 21:34:22 +09:30
parent bda52c315c
commit 4eafc1a2e1

View File

@@ -51,6 +51,12 @@ HTABLE_DEFINE_NODUPS_TYPE(struct peer_backup,
peer_backup_eq_node_id,
backup_map);
HTABLE_DEFINE_NODUPS_TYPE(struct node_id,
node_id_keyof,
node_id_hash,
node_id_eq,
peer_map);
struct chanbackup {
bool peer_backup;
/* Global secret object to keep the derived encryption key for the SCB */
@@ -58,6 +64,9 @@ struct chanbackup {
/* Cache of backups for each peer we know about */
struct backup_map *backups;
/* Cache of known peers which support backups (for sending) */
struct peer_map *peers;
};
static struct chanbackup *chanbackup(struct plugin *plugin)
@@ -77,6 +86,19 @@ static struct peer_backup *add_to_backup_map(struct chanbackup *cb,
return pb;
}
static void remove_peer(struct plugin *plugin, const struct node_id *node_id)
{
struct chanbackup *cb = chanbackup(plugin);
struct node_id *peer;
/* Eliminate it (probably it's disconnected) */
peer = peer_map_get(cb->peers, node_id);
if (peer) {
peer_map_del(cb->peers, peer);
tal_free(peer);
}
}
/* Helper to fetch out SCB from the RPC call */
static bool json_to_scb_chan(const char *buffer,
const jsmntok_t *tok,
@@ -406,7 +428,7 @@ static struct command_result
const char *method,
const char *buf,
const jsmntok_t *params,
void *cb_arg UNUSED)
struct node_id *node_id)
{
plugin_log(cmd->plugin, LOG_DBG, "Sent their peer storage!");
return command_hook_success(cmd);
@@ -417,9 +439,10 @@ static struct command_result
const char *method,
const char *buf,
const jsmntok_t *params,
void *cb_arg UNUSED)
struct node_id *node_id)
{
plugin_log(cmd->plugin, LOG_DBG, "Unable to send Peer storage!");
remove_peer(cmd->plugin, node_id);
return command_hook_success(cmd);
}
@@ -450,7 +473,7 @@ static struct command_result *peer_after_send_scb(struct command *cmd,
"sendcustommsg",
peer_after_send_their_peer_strg,
peer_after_send_their_peer_strg_err,
NULL);
nodeid);
json_add_node_id(req->js, "node_id", nodeid);
json_add_hex_talarr(req->js, "msg", msg);
@@ -466,11 +489,13 @@ static struct command_result *peer_after_send_scb_failed(struct command *cmd,
{
plugin_log(cmd->plugin, LOG_DBG, "Peer storage send failed %.*s!",
json_tok_full_len(params), json_tok_full(buf, params));
remove_peer(cmd->plugin, nodeid);
return command_hook_success(cmd);
}
struct info {
size_t idx;
size_t *idx;
struct node_id node_id;
};
/* We refresh scb from both channel_state_changed notification and
@@ -491,7 +516,7 @@ static struct command_result *after_send_scb_single(struct command *cmd,
struct info *info)
{
plugin_log(cmd->plugin, LOG_TRACE, "Peer storage sent!");
if (--info->idx != 0)
if (--(*info->idx) != 0)
return command_still_pending(cmd);
return notification_or_hook_done(cmd);
@@ -504,7 +529,8 @@ static struct command_result *after_send_scb_single_fail(struct command *cmd,
struct info *info)
{
plugin_log(cmd->plugin, LOG_DBG, "Peer storage send failed!");
if (--info->idx != 0)
remove_peer(cmd->plugin, &info->node_id);
if (--(*info->idx) != 0)
return command_still_pending(cmd);
return notification_or_hook_done(cmd);
@@ -519,7 +545,7 @@ static struct command_result *after_listpeers(struct command *cmd,
const jsmntok_t *peers, *peer;
struct out_req *req;
size_t i;
struct info *info = tal(cmd, struct info);
size_t *idx = tal(cmd, size_t);
bool is_connected;
u8 *serialise_scb;
@@ -540,7 +566,7 @@ static struct command_result *after_listpeers(struct command *cmd,
peers = json_get_member(buf, params, "peers");
info->idx = 0;
*idx = 0;
json_for_each_arr(i, peer, peers) {
const char *err;
u8 *features;
@@ -557,10 +583,11 @@ static struct command_result *after_listpeers(struct command *cmd,
/* We shouldn't have to check, but LND hangs up? */
if (feature_offered(features, OPT_PROVIDE_STORAGE)) {
const jsmntok_t *nodeid;
struct node_id node_id;
struct info *info = tal(cmd, struct info);
info->idx = idx;
nodeid = json_get_member(buf, peer, "id");
json_to_node_id(buf, nodeid, &node_id);
json_to_node_id(buf, nodeid, &info->node_id);
req = jsonrpc_request_start(cmd,
"sendcustommsg",
@@ -568,14 +595,14 @@ static struct command_result *after_listpeers(struct command *cmd,
after_send_scb_single_fail,
info);
json_add_node_id(req->js, "node_id", &node_id);
json_add_node_id(req->js, "node_id", &info->node_id);
json_add_hex_talarr(req->js, "msg", serialise_scb);
info->idx++;
(*info->idx)++;
send_outreq(req);
}
}
if (info->idx == 0)
if (*idx == 0)
return notification_or_hook_done(cmd);
return command_still_pending(cmd);
}
@@ -674,8 +701,9 @@ static struct command_result *peer_connected(struct command *cmd,
u8 *serialise_scb;
const char *err;
u8 *features;
struct chanbackup *cb = chanbackup(cmd->plugin);
if (!chanbackup(cmd->plugin)->peer_backup)
if (!cb->peer_backup)
return command_hook_success(cmd);
serialise_scb = towire_peer_storage(cmd,
@@ -697,6 +725,10 @@ static struct command_result *peer_connected(struct command *cmd,
return command_hook_success(cmd);
}
/* Remember this peer for future sends */
if (!peer_map_get(cb->peers, node_id))
peer_map_add(cb->peers, tal_dup(cb->peers, struct node_id, node_id));
req = jsonrpc_request_start(cmd,
"sendcustommsg",
peer_after_send_scb,
@@ -978,6 +1010,8 @@ static void setup_backup_map(struct command *init_cmd,
cb->backups = tal(cb, struct backup_map);
backup_map_init(cb->backups);
cb->peers = tal(cb, struct peer_map);
peer_map_init(cb->peers);
json_out_start(params, NULL, '{');
json_out_start(params, "key", '[');
@@ -1023,6 +1057,7 @@ static void chanbackup_mark_mem(struct plugin *plugin,
{
const struct chanbackup *cb = chanbackup(plugin);
memleak_scan_htable(memtable, &cb->backups->raw);
memleak_scan_htable(memtable, &cb->peers->raw);
}
static const char *init(struct command *init_cmd,