offers: make find_best_peer take a feature bitmap.
What changed, and why it matters
This is a small internal refactoring change in the Core Lightning 'offers' plugin. It changes one helper function so it can check for multiple peer features at once (using a bitmap) instead of only one feature at a time. The callers are updated to pass their single feature as a bitmap bit. There is no security fix or behavior change visible to users.
No security action needed. Treat as normal code maintenance.
Security signals we found
No strong security signals were identified.
Evidence from the diff
The commit refactors find_best_peer() in plugins/offers.c to accept a u64 feature bitmap (needed_features) rather than a single int feature index. The loop over listincoming results now iterates every set bit and skips peers missing any required feature. Callers in offers_invreq_hook.c and offers_offer.c are updated from passing the feature enum directly (e.g., OPT_ROUTE_BLINDING) to passing 1ULL << OPT_ROUTE_BLINDING. No new features are required, no validation logic is relaxed, and no security boundary is changed.
Changed components
plugins/offers.cplugins/offers.hplugins/offers_invreq_hook.cplugins/offers_offer.cInspect captured patch +22 / −11
diff --git a/plugins/offers.c b/plugins/offers.c
index 735ba87b..2cefc1ff 100644
--- a/plugins/offers.c
+++ b/plugins/offers.c
@@ -1,6 +1,7 @@
/* This plugin covers both sending and receiving offers */
#include "config.h"
#include <ccan/array_size/array_size.h>
+#include <ccan/bitops/bitops.h>
#include <ccan/rune/rune.h>
#include <ccan/tal/str/str.h>
#include <common/bech32.h>
@@ -314,7 +315,7 @@ struct find_best_peer_data {
struct command_result *(*cb)(struct command *,
const struct chaninfo *,
void *);
- int needed_feature;
+ u64 needed_features;
void *arg;
};
@@ -333,6 +334,7 @@ static struct command_result *listincoming_done(struct command *cmd,
struct chaninfo ci;
const jsmntok_t *pftok;
u8 *features;
+ u64 feature_bits;
const char *err;
struct amount_msat feebase;
bool enabled;
@@ -373,11 +375,20 @@ static struct command_result *listincoming_done(struct command *cmd,
if (!pftok)
continue;
features = json_tok_bin_from_hex(tmpctx, buf, pftok);
- if (!feature_offered(features, data->needed_feature))
- continue;
+
+ /* It must have all the features we need */
+ feature_bits = data->needed_features;
+ while (feature_bits) {
+ int feature = bitops_ls64(feature_bits);
+ if (!feature_offered(features, feature))
+ goto next;
+ feature_bits &= ~(1ULL << feature);
+ }
if (!best || amount_msat_greater(ci.capacity, best->capacity))
best = tal_dup(tmpctx, struct chaninfo, &ci);
+
+ next:;
}
/* Free data if they don't */
@@ -386,7 +397,7 @@ static struct command_result *listincoming_done(struct command *cmd,
}
struct command_result *find_best_peer_(struct command *cmd,
- int needed_feature,
+ u64 needed_features,
struct command_result *(*cb)(struct command *,
const struct chaninfo *,
void *),
@@ -396,7 +407,7 @@ struct command_result *find_best_peer_(struct command *cmd,
struct find_best_peer_data *data = tal(cmd, struct find_best_peer_data);
data->cb = cb;
data->arg = arg;
- data->needed_feature = needed_feature;
+ data->needed_features = needed_features;
req = jsonrpc_request_start(cmd, "listincoming",
listincoming_done, forward_error, data);
return send_outreq(req);
diff --git a/plugins/offers.h b/plugins/offers.h
index e59796a9..b7be946f 100644
--- a/plugins/offers.h
+++ b/plugins/offers.h
@@ -78,14 +78,14 @@ struct chaninfo {
/* Calls listpeerchannels, then cb with best peer (if any!) which has needed_feature */
struct command_result *find_best_peer_(struct command *cmd,
- int needed_feature,
+ u64 needed_features,
struct command_result *(*cb)(struct command *,
const struct chaninfo *,
void *),
void *arg);
-#define find_best_peer(cmd, needed_feature, cb, arg) \
- find_best_peer_((cmd), (needed_feature), \
+#define find_best_peer(cmd, needed_features, cb, arg) \
+ find_best_peer_((cmd), (needed_features), \
typesafe_cb_preargs(struct command_result *, void *, \
(cb), (arg), \
struct command *, \
diff --git a/plugins/offers_invreq_hook.c b/plugins/offers_invreq_hook.c
index 6f8bcc10..d57b7f95 100644
--- a/plugins/offers_invreq_hook.c
+++ b/plugins/offers_invreq_hook.c
@@ -381,7 +381,7 @@ static struct command_result *add_blindedpaths(struct command *cmd,
if (!we_want_blinded_path(cmd->plugin, true))
return create_invoicereq(cmd, ir);
- return find_best_peer(cmd, OPT_ROUTE_BLINDING,
+ return find_best_peer(cmd, 1ULL << OPT_ROUTE_BLINDING,
found_best_peer, ir);
}
diff --git a/plugins/offers_offer.c b/plugins/offers_offer.c
index 53c88f05..8bad8249 100644
--- a/plugins/offers_offer.c
+++ b/plugins/offers_offer.c
@@ -303,7 +303,7 @@ static struct command_result *maybe_add_path(struct command *cmd,
*/
if (!offinfo->offer->offer_paths) {
if (we_want_blinded_path(cmd->plugin, false))
- return find_best_peer(cmd, OPT_ONION_MESSAGES,
+ return find_best_peer(cmd, 1ULL << OPT_ONION_MESSAGES,
found_best_peer, offinfo);
}
return create_offer(cmd, offinfo);
@@ -729,7 +729,7 @@ struct command_result *json_invoicerequest(struct command *cmd,
idata->invreq = invreq;
idata->single_use = *single_use;
idata->label = label;
- return find_best_peer(cmd, OPT_ONION_MESSAGES,
+ return find_best_peer(cmd, 1ULL << OPT_ONION_MESSAGES,
found_best_peer_invrequest, idata);
}
Why this scored 15/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.