lightningd: don't hand 0 to dualopend as anchor feerate if we cannot estimate fees.
What changed, and why it matters
This patch fixes a crash in Core Lightning's experimental dual-funding feature. When the node couldn't estimate current Bitcoin transaction fees, it was passing a value of 0 to a sub-component (dualopend) as the 'anchor feerate.' That zero value caused the process to crash. The fix detects the zero, substitutes a minimum fallback feerate, and adds a safety check to ensure it is never zero.
Upgrade to a release containing this commit if you run dual-funded channel opens. The crash is triggered only when fee estimation fails, so ensuring a reliable fee source also mitigates the issue. No immediate remote-exploitation concern is evident from the diff.
Security signals we found
Denial-of-service vector: passing an invalid 0 feerate crashes the dualopend subdaemon
Input validation gap: missing handling of 'unknown' fee-estimation return value
Crash triggered during dual-funded channel open when fee estimator has no data
Fix uses a guaranteed non-zero floor feerate as a safe fallback
Evidence from the diff
In lightningd/dual_open_control.c, both openchannel_init() and json_queryrates() previously called unilateral_feerate(topology, true) directly and passed the result to towire_dualopend_opener_init() as the anchor feerate. unilateral_feerate() can return 0 when fee estimation is unavailable, and 0 was being interpreted as a valid feerate by dualopend, leading to a crash. The patch introduces a local anchor_feerate variable, checks for 0, falls back to get_feerate_floor(), and asserts the result is non-zero before passing it to dualopend.
Changed components
lightningd/dual_open_control.cdualopend subdaemon (consumer of the wire message)Experimental dual-funded channel opening (openchannel_init, json_queryrates)Inspect captured patch +18 / −3
diff --git a/lightningd/dual_open_control.c b/lightningd/dual_open_control.c
index 628b9c90..3ea21b36 100644
--- a/lightningd/dual_open_control.c
+++ b/lightningd/dual_open_control.c
@@ -3046,6 +3046,7 @@ static struct command_result *openchannel_init(struct command *cmd,
{
u32 *our_upfront_shutdown_script_wallet_index;
u32 found_wallet_index;
+ u32 anchor_feerate;
struct channel *channel;
struct open_attempt *oa;
int fds[2];
@@ -3093,12 +3094,19 @@ static struct command_result *openchannel_init(struct command *cmd,
} else
our_upfront_shutdown_script_wallet_index = NULL;
+ /* 0 from this means "unknown" */
+ anchor_feerate = unilateral_feerate(cmd->ld->topology, true);
+ if (anchor_feerate == 0) {
+ anchor_feerate = get_feerate_floor(cmd->ld->topology);
+ assert(anchor_feerate);
+ }
+
oa->open_msg = towire_dualopend_opener_init(oa,
psbt, amount,
oa->our_upfront_shutdown_script,
our_upfront_shutdown_script_wallet_index,
feerate_per_kw,
- unilateral_feerate(cmd->ld->topology, true),
+ anchor_feerate,
feerate_per_kw_funding,
channel->channel_flags,
amount_sat_is_zero(request_amt) ?
@@ -3803,7 +3811,7 @@ static struct command_result *json_queryrates(struct command *cmd,
struct peer *peer;
struct channel *channel;
u32 *feerate_per_kw_funding;
- u32 *feerate_per_kw;
+ u32 *feerate_per_kw, anchor_feerate;
struct amount_sat *amount, *request_amt;
struct wally_psbt *psbt;
struct open_attempt *oa;
@@ -3891,12 +3899,19 @@ static struct command_result *json_queryrates(struct command *cmd,
} else
our_upfront_shutdown_script_wallet_index = NULL;
+ /* 0 from this means "unknown" */
+ anchor_feerate = unilateral_feerate(cmd->ld->topology, true);
+ if (anchor_feerate == 0) {
+ anchor_feerate = get_feerate_floor(cmd->ld->topology);
+ assert(anchor_feerate);
+ }
+
oa->open_msg = towire_dualopend_opener_init(oa,
psbt, *amount,
oa->our_upfront_shutdown_script,
our_upfront_shutdown_script_wallet_index,
*feerate_per_kw,
- unilateral_feerate(cmd->ld->topology, true),
+ anchor_feerate,
*feerate_per_kw_funding,
channel->channel_flags,
amount_sat_is_zero(*request_amt) ?
Why this scored 44/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.