Simplify calculation of the biggest HTLC value that can be sent next
What changed, and why it matters
This is a small code cleanup in the Lightning payment channel logic. The developer rewrote how the maximum next HTLC (payment) amount is calculated, using simpler arithmetic and removing a debug assertion. The commit message explicitly states there are no functional changes, and the diff appears to preserve the same end result while making the code easier to read.
No security action required. Treat as a normal refactoring commit. If desired, reviewers can verify equivalence through unit tests covering dust-limit and fee-difference edge cases.
Security signals we found
No strong security signals were identified.
Evidence from the diff
In lightning/src/ln/channel.rs, the calculation of the largest HTLC that can be sent next was refactored. The old code subtracted the maximum reserved commitment fee as a signed i64, checked against the dust limit, then conditionally added back the difference between max and min reserved fees and clamped the result. The new code uses unsigned saturating_sub to avoid negative intermediate values, directly computes capacity_minus_min_commitment_fee_msat when below the dust threshold, and removes the debug_assert!(one_htlc_difference_msat != 0). The logic appears semantically equivalent: if subtracting the max fee leaves a value below dust, it falls back to the min-fee case and clamps just below dust; otherwise it uses the max-fee case. No security-relevant behavior change is evident from the diff alone.
Changed components
lightning/src/ln/channel.rsHTLC send-amount calculationInspect captured patch +5 / −9
diff --git a/lightning/src/ln/channel.rs b/lightning/src/ln/channel.rs
index 7943ed9..2416981 100644
--- a/lightning/src/ln/channel.rs
+++ b/lightning/src/ln/channel.rs
@@ -5938,16 +5938,12 @@ impl<SP: SignerProvider> ChannelContext<SP> {
// We will first subtract the fee as if we were above-dust. Then, if the resulting
// value ends up being below dust, we have this fee available again. In that case,
// match the value to right-below-dust.
- let mut capacity_minus_commitment_fee_msat: i64 = available_capacity_msat as i64 -
- max_reserved_commit_tx_fee_msat as i64;
- if capacity_minus_commitment_fee_msat < (real_dust_limit_timeout_sat as i64) * 1000 {
- let one_htlc_difference_msat = max_reserved_commit_tx_fee_msat - min_reserved_commit_tx_fee_msat;
- debug_assert!(one_htlc_difference_msat != 0);
- capacity_minus_commitment_fee_msat += one_htlc_difference_msat as i64;
- capacity_minus_commitment_fee_msat = cmp::min(real_dust_limit_timeout_sat as i64 * 1000 - 1, capacity_minus_commitment_fee_msat);
- available_capacity_msat = cmp::max(0, cmp::min(capacity_minus_commitment_fee_msat, available_capacity_msat as i64)) as u64;
+ let capacity_minus_max_commitment_fee_msat = available_capacity_msat.saturating_sub(max_reserved_commit_tx_fee_msat);
+ if capacity_minus_max_commitment_fee_msat < real_dust_limit_timeout_sat * 1000 {
+ let capacity_minus_min_commitment_fee_msat = available_capacity_msat.saturating_sub(min_reserved_commit_tx_fee_msat);
+ available_capacity_msat = cmp::min(real_dust_limit_timeout_sat * 1000 - 1, capacity_minus_min_commitment_fee_msat);
} else {
- available_capacity_msat = capacity_minus_commitment_fee_msat as u64;
+ available_capacity_msat = capacity_minus_max_commitment_fee_msat;
}
} else {
// If the channel is inbound (i.e. counterparty pays the fee), we need to make sure
Why this scored 11/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.