lightningd: add payment-fronting-node option.
What changed, and why it matters
This commit adds a new optional configuration setting called `payment-fronting-node` to Core Lightning. It lets a node operator choose one or more neighboring nodes to appear as the entry point on invoices and offers, routing payments to themselves through those neighbors. This is a privacy feature, not a security fix or vulnerability.
No security action required. Treat as a normal feature addition. Review the follow-up commits that consume `fronting_nodes` to ensure routehint/blinded-path construction is implemented safely.
Security signals we found
No strong security signals were identified.
Evidence from the diff
The patch introduces the --payment-fronting-node CLI/config option, stored as an array of struct node_id in struct lightningd. It registers the option with multi-value support and a parser (opt_add_node_id) that validates hex node IDs. Documentation explains that for BOLT11 invoices a routehint with an alias short channel ID is used, while BOLT12 invoices/offers use a blinded path from the fronting node. No logic for actually constructing these route hints or blinded paths is present in this commit; it only adds the option plumbing.
Changed components
lightningd option parsinglightningd configuration stateinvoice/offer generation plumbing (future consumer)Inspect captured patch +23 / −0
diff --git a/doc/lightningd-config.5.md b/doc/lightningd-config.5.md
index 38f43312..7d6398c8 100644
--- a/doc/lightningd-config.5.md
+++ b/doc/lightningd-config.5.md
@@ -539,6 +539,10 @@ delete the others.
### Payment and invoice control options:
+* **payment-fronting-node**=*nodeid*
+
+ Always use this *nodeid* as the entry point when we generate invoices or offers: currently, the node must be a neighbor we have a channel with. For BOLT11 invoices we will use a routehint with the alias for the short channel id to provide limited privacy (we still reveal our node id). For BOLT12 invoices and offers, we provide a blinded path from the node to us which provides better privacy. This can be specified multiple times for multiple fronting nodes.
+
* **disable-mpp** [plugin `pay`]
Disable the multi-part payment sending support in the `pay` plugin. By default
diff --git a/lightningd/lightningd.c b/lightningd/lightningd.c
index 5d642985..f23fb7df 100644
--- a/lightningd/lightningd.c
+++ b/lightningd/lightningd.c
@@ -372,6 +372,7 @@ static struct lightningd *new_lightningd(const tal_t *ctx)
/* The gossip seeker automatically connects to a this many peers */
ld->autoconnect_seeker_peers = 10;
+ ld->fronting_nodes = tal_arr(ld, struct node_id, 0);
return ld;
}
diff --git a/lightningd/lightningd.h b/lightningd/lightningd.h
index a9a8c165..79613faa 100644
--- a/lightningd/lightningd.h
+++ b/lightningd/lightningd.h
@@ -434,6 +434,9 @@ struct lightningd {
/* Minimum number of peers seeker should maintain. */
u32 autoconnect_seeker_peers;
+
+ /* Nodes to use for invoices / offers */
+ struct node_id *fronting_nodes;
};
/* Turning this on allows a tal allocation to return NULL, rather than aborting.
diff --git a/lightningd/options.c b/lightningd/options.c
index 95892dce..d9ef8e44 100644
--- a/lightningd/options.c
+++ b/lightningd/options.c
@@ -1282,6 +1282,16 @@ static char *opt_add_api_beg(const char *arg, struct lightningd *ld)
return NULL;
}
+static char *opt_add_node_id(const char *arg, struct node_id **arr)
+{
+ struct node_id n;
+ if (!node_id_from_hexstr(arg, strlen(arg), &n))
+ return "Unparsable nodeid";
+
+ tal_arr_expand(arr, n);
+ return NULL;
+}
+
char *hsm_secret_arg(const tal_t *ctx,
const char *arg,
const struct hsm_secret **hsm_secret)
@@ -1636,6 +1646,10 @@ static void register_opts(struct lightningd *ld)
ld,
"Re-enable a long-deprecated API (which will be removed entirely next version!)");
opt_register_logging(ld);
+ clnopt_witharg("--payment-fronting-node",
+ OPT_MULTI,
+ opt_add_node_id, NULL,
+ &ld->fronting_nodes, "Put this node in all invoices and offers, and use blinded path (bolt12) or route hints (bolt11) to route to this node. Must be a neighboring node. Can be specified multiple times.");
/* Old bookkeeper migration flags. */
opt_register_early_arg("--bookkeeper-dir",
@@ -1902,6 +1916,7 @@ bool is_known_opt_cb_arg(char *(*cb_arg)(const char *, void *))
|| cb_arg == (void *)opt_subd_dev_disconnect
|| cb_arg == (void *)opt_set_crash_timeout
|| cb_arg == (void *)opt_add_api_beg
+ || cb_arg == (void *)opt_add_node_id
|| cb_arg == (void *)opt_force_featureset
|| cb_arg == (void *)opt_force_privkey
|| cb_arg == (void *)opt_force_bip32_seed
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.