Skip to content

Commit 60706d6

Browse files
committed
Move Channel::get_available_balances to ChannelContext impl
1 parent 9f4e714 commit 60706d6

File tree

2 files changed

+139
-139
lines changed

2 files changed

+139
-139
lines changed

lightning/src/ln/channel.rs

Lines changed: 138 additions & 138 deletions
Original file line numberDiff line numberDiff line change
@@ -1451,6 +1451,143 @@ impl<Signer: ChannelSigner> ChannelContext<Signer> {
14511451
stats
14521452
}
14531453

1454+
/// Get the available balances, see [`AvailableBalances`]'s fields for more info.
1455+
/// Doesn't bother handling the
1456+
/// if-we-removed-it-already-but-haven't-fully-resolved-they-can-still-send-an-inbound-HTLC
1457+
/// corner case properly.
1458+
pub fn get_available_balances(&self) -> AvailableBalances {
1459+
let context = &self;
1460+
// Note that we have to handle overflow due to the above case.
1461+
let inbound_stats = context.get_inbound_pending_htlc_stats(None);
1462+
let outbound_stats = context.get_outbound_pending_htlc_stats(None);
1463+
1464+
let mut balance_msat = context.value_to_self_msat;
1465+
for ref htlc in context.pending_inbound_htlcs.iter() {
1466+
if let InboundHTLCState::LocalRemoved(InboundHTLCRemovalReason::Fulfill(_)) = htlc.state {
1467+
balance_msat += htlc.amount_msat;
1468+
}
1469+
}
1470+
balance_msat -= outbound_stats.pending_htlcs_value_msat;
1471+
1472+
let outbound_capacity_msat = context.value_to_self_msat
1473+
.saturating_sub(outbound_stats.pending_htlcs_value_msat)
1474+
.saturating_sub(
1475+
context.counterparty_selected_channel_reserve_satoshis.unwrap_or(0) * 1000);
1476+
1477+
let mut available_capacity_msat = outbound_capacity_msat;
1478+
1479+
if context.is_outbound() {
1480+
// We should mind channel commit tx fee when computing how much of the available capacity
1481+
// can be used in the next htlc. Mirrors the logic in send_htlc.
1482+
//
1483+
// The fee depends on whether the amount we will be sending is above dust or not,
1484+
// and the answer will in turn change the amount itself — making it a circular
1485+
// dependency.
1486+
// This complicates the computation around dust-values, up to the one-htlc-value.
1487+
let mut real_dust_limit_timeout_sat = context.holder_dust_limit_satoshis;
1488+
if !context.opt_anchors() {
1489+
real_dust_limit_timeout_sat += context.feerate_per_kw as u64 * htlc_timeout_tx_weight(false) / 1000;
1490+
}
1491+
1492+
let htlc_above_dust = HTLCCandidate::new(real_dust_limit_timeout_sat * 1000, HTLCInitiator::LocalOffered);
1493+
let max_reserved_commit_tx_fee_msat = FEE_SPIKE_BUFFER_FEE_INCREASE_MULTIPLE * context.next_local_commit_tx_fee_msat(htlc_above_dust, Some(()));
1494+
let htlc_dust = HTLCCandidate::new(real_dust_limit_timeout_sat * 1000 - 1, HTLCInitiator::LocalOffered);
1495+
let min_reserved_commit_tx_fee_msat = FEE_SPIKE_BUFFER_FEE_INCREASE_MULTIPLE * context.next_local_commit_tx_fee_msat(htlc_dust, Some(()));
1496+
1497+
// We will first subtract the fee as if we were above-dust. Then, if the resulting
1498+
// value ends up being below dust, we have this fee available again. In that case,
1499+
// match the value to right-below-dust.
1500+
let mut capacity_minus_commitment_fee_msat: i64 = (available_capacity_msat as i64) - (max_reserved_commit_tx_fee_msat as i64);
1501+
if capacity_minus_commitment_fee_msat < (real_dust_limit_timeout_sat as i64) * 1000 {
1502+
let one_htlc_difference_msat = max_reserved_commit_tx_fee_msat - min_reserved_commit_tx_fee_msat;
1503+
debug_assert!(one_htlc_difference_msat != 0);
1504+
capacity_minus_commitment_fee_msat += one_htlc_difference_msat as i64;
1505+
capacity_minus_commitment_fee_msat = cmp::min(real_dust_limit_timeout_sat as i64 * 1000 - 1, capacity_minus_commitment_fee_msat);
1506+
available_capacity_msat = cmp::max(0, cmp::min(capacity_minus_commitment_fee_msat, available_capacity_msat as i64)) as u64;
1507+
} else {
1508+
available_capacity_msat = capacity_minus_commitment_fee_msat as u64;
1509+
}
1510+
} else {
1511+
// If the channel is inbound (i.e. counterparty pays the fee), we need to make sure
1512+
// sending a new HTLC won't reduce their balance below our reserve threshold.
1513+
let mut real_dust_limit_success_sat = context.counterparty_dust_limit_satoshis;
1514+
if !context.opt_anchors() {
1515+
real_dust_limit_success_sat += context.feerate_per_kw as u64 * htlc_success_tx_weight(false) / 1000;
1516+
}
1517+
1518+
let htlc_above_dust = HTLCCandidate::new(real_dust_limit_success_sat * 1000, HTLCInitiator::LocalOffered);
1519+
let max_reserved_commit_tx_fee_msat = context.next_remote_commit_tx_fee_msat(htlc_above_dust, None);
1520+
1521+
let holder_selected_chan_reserve_msat = context.holder_selected_channel_reserve_satoshis * 1000;
1522+
let remote_balance_msat = (context.channel_value_satoshis * 1000 - context.value_to_self_msat)
1523+
.saturating_sub(inbound_stats.pending_htlcs_value_msat);
1524+
1525+
if remote_balance_msat < max_reserved_commit_tx_fee_msat + holder_selected_chan_reserve_msat {
1526+
// If another HTLC's fee would reduce the remote's balance below the reserve limit
1527+
// we've selected for them, we can only send dust HTLCs.
1528+
available_capacity_msat = cmp::min(available_capacity_msat, real_dust_limit_success_sat * 1000 - 1);
1529+
}
1530+
}
1531+
1532+
let mut next_outbound_htlc_minimum_msat = context.counterparty_htlc_minimum_msat;
1533+
1534+
// If we get close to our maximum dust exposure, we end up in a situation where we can send
1535+
// between zero and the remaining dust exposure limit remaining OR above the dust limit.
1536+
// Because we cannot express this as a simple min/max, we prefer to tell the user they can
1537+
// send above the dust limit (as the router can always overpay to meet the dust limit).
1538+
let mut remaining_msat_below_dust_exposure_limit = None;
1539+
let mut dust_exposure_dust_limit_msat = 0;
1540+
1541+
let (htlc_success_dust_limit, htlc_timeout_dust_limit) = if context.opt_anchors() {
1542+
(context.counterparty_dust_limit_satoshis, context.holder_dust_limit_satoshis)
1543+
} else {
1544+
let dust_buffer_feerate = context.get_dust_buffer_feerate(None) as u64;
1545+
(context.counterparty_dust_limit_satoshis + dust_buffer_feerate * htlc_success_tx_weight(false) / 1000,
1546+
context.holder_dust_limit_satoshis + dust_buffer_feerate * htlc_timeout_tx_weight(false) / 1000)
1547+
};
1548+
let on_counterparty_dust_htlc_exposure_msat = inbound_stats.on_counterparty_tx_dust_exposure_msat + outbound_stats.on_counterparty_tx_dust_exposure_msat;
1549+
if on_counterparty_dust_htlc_exposure_msat as i64 + htlc_success_dust_limit as i64 * 1000 - 1 > context.get_max_dust_htlc_exposure_msat() as i64 {
1550+
remaining_msat_below_dust_exposure_limit =
1551+
Some(context.get_max_dust_htlc_exposure_msat().saturating_sub(on_counterparty_dust_htlc_exposure_msat));
1552+
dust_exposure_dust_limit_msat = cmp::max(dust_exposure_dust_limit_msat, htlc_success_dust_limit * 1000);
1553+
}
1554+
1555+
let on_holder_dust_htlc_exposure_msat = inbound_stats.on_holder_tx_dust_exposure_msat + outbound_stats.on_holder_tx_dust_exposure_msat;
1556+
if on_holder_dust_htlc_exposure_msat as i64 + htlc_timeout_dust_limit as i64 * 1000 - 1 > context.get_max_dust_htlc_exposure_msat() as i64 {
1557+
remaining_msat_below_dust_exposure_limit = Some(cmp::min(
1558+
remaining_msat_below_dust_exposure_limit.unwrap_or(u64::max_value()),
1559+
context.get_max_dust_htlc_exposure_msat().saturating_sub(on_holder_dust_htlc_exposure_msat)));
1560+
dust_exposure_dust_limit_msat = cmp::max(dust_exposure_dust_limit_msat, htlc_timeout_dust_limit * 1000);
1561+
}
1562+
1563+
if let Some(remaining_limit_msat) = remaining_msat_below_dust_exposure_limit {
1564+
if available_capacity_msat < dust_exposure_dust_limit_msat {
1565+
available_capacity_msat = cmp::min(available_capacity_msat, remaining_limit_msat);
1566+
} else {
1567+
next_outbound_htlc_minimum_msat = cmp::max(next_outbound_htlc_minimum_msat, dust_exposure_dust_limit_msat);
1568+
}
1569+
}
1570+
1571+
available_capacity_msat = cmp::min(available_capacity_msat,
1572+
context.counterparty_max_htlc_value_in_flight_msat - outbound_stats.pending_htlcs_value_msat);
1573+
1574+
if outbound_stats.pending_htlcs + 1 > context.counterparty_max_accepted_htlcs as u32 {
1575+
available_capacity_msat = 0;
1576+
}
1577+
1578+
AvailableBalances {
1579+
inbound_capacity_msat: cmp::max(context.channel_value_satoshis as i64 * 1000
1580+
- context.value_to_self_msat as i64
1581+
- context.get_inbound_pending_htlc_stats(None).pending_htlcs_value_msat as i64
1582+
- context.holder_selected_channel_reserve_satoshis as i64 * 1000,
1583+
0) as u64,
1584+
outbound_capacity_msat,
1585+
next_outbound_htlc_limit_msat: available_capacity_msat,
1586+
next_outbound_htlc_minimum_msat,
1587+
balance_msat,
1588+
}
1589+
}
1590+
14541591
pub fn get_holder_counterparty_selected_channel_reserve_satoshis(&self) -> (u64, Option<u64>) {
14551592
let context = &self;
14561593
(context.holder_selected_channel_reserve_satoshis, context.counterparty_selected_channel_reserve_satoshis)
@@ -3222,143 +3359,6 @@ impl<Signer: WriteableEcdsaChannelSigner> Channel<Signer> {
32223359
}
32233360
}
32243361

3225-
/// Get the available balances, see [`AvailableBalances`]'s fields for more info.
3226-
/// Doesn't bother handling the
3227-
/// if-we-removed-it-already-but-haven't-fully-resolved-they-can-still-send-an-inbound-HTLC
3228-
/// corner case properly.
3229-
pub fn get_available_balances(&self) -> AvailableBalances {
3230-
let context = &self.context;
3231-
// Note that we have to handle overflow due to the above case.
3232-
let inbound_stats = context.get_inbound_pending_htlc_stats(None);
3233-
let outbound_stats = context.get_outbound_pending_htlc_stats(None);
3234-
3235-
let mut balance_msat = context.value_to_self_msat;
3236-
for ref htlc in context.pending_inbound_htlcs.iter() {
3237-
if let InboundHTLCState::LocalRemoved(InboundHTLCRemovalReason::Fulfill(_)) = htlc.state {
3238-
balance_msat += htlc.amount_msat;
3239-
}
3240-
}
3241-
balance_msat -= outbound_stats.pending_htlcs_value_msat;
3242-
3243-
let outbound_capacity_msat = context.value_to_self_msat
3244-
.saturating_sub(outbound_stats.pending_htlcs_value_msat)
3245-
.saturating_sub(
3246-
context.counterparty_selected_channel_reserve_satoshis.unwrap_or(0) * 1000);
3247-
3248-
let mut available_capacity_msat = outbound_capacity_msat;
3249-
3250-
if context.is_outbound() {
3251-
// We should mind channel commit tx fee when computing how much of the available capacity
3252-
// can be used in the next htlc. Mirrors the logic in send_htlc.
3253-
//
3254-
// The fee depends on whether the amount we will be sending is above dust or not,
3255-
// and the answer will in turn change the amount itself — making it a circular
3256-
// dependency.
3257-
// This complicates the computation around dust-values, up to the one-htlc-value.
3258-
let mut real_dust_limit_timeout_sat = context.holder_dust_limit_satoshis;
3259-
if !context.opt_anchors() {
3260-
real_dust_limit_timeout_sat += context.feerate_per_kw as u64 * htlc_timeout_tx_weight(false) / 1000;
3261-
}
3262-
3263-
let htlc_above_dust = HTLCCandidate::new(real_dust_limit_timeout_sat * 1000, HTLCInitiator::LocalOffered);
3264-
let max_reserved_commit_tx_fee_msat = FEE_SPIKE_BUFFER_FEE_INCREASE_MULTIPLE * context.next_local_commit_tx_fee_msat(htlc_above_dust, Some(()));
3265-
let htlc_dust = HTLCCandidate::new(real_dust_limit_timeout_sat * 1000 - 1, HTLCInitiator::LocalOffered);
3266-
let min_reserved_commit_tx_fee_msat = FEE_SPIKE_BUFFER_FEE_INCREASE_MULTIPLE * context.next_local_commit_tx_fee_msat(htlc_dust, Some(()));
3267-
3268-
// We will first subtract the fee as if we were above-dust. Then, if the resulting
3269-
// value ends up being below dust, we have this fee available again. In that case,
3270-
// match the value to right-below-dust.
3271-
let mut capacity_minus_commitment_fee_msat: i64 = (available_capacity_msat as i64) - (max_reserved_commit_tx_fee_msat as i64);
3272-
if capacity_minus_commitment_fee_msat < (real_dust_limit_timeout_sat as i64) * 1000 {
3273-
let one_htlc_difference_msat = max_reserved_commit_tx_fee_msat - min_reserved_commit_tx_fee_msat;
3274-
debug_assert!(one_htlc_difference_msat != 0);
3275-
capacity_minus_commitment_fee_msat += one_htlc_difference_msat as i64;
3276-
capacity_minus_commitment_fee_msat = cmp::min(real_dust_limit_timeout_sat as i64 * 1000 - 1, capacity_minus_commitment_fee_msat);
3277-
available_capacity_msat = cmp::max(0, cmp::min(capacity_minus_commitment_fee_msat, available_capacity_msat as i64)) as u64;
3278-
} else {
3279-
available_capacity_msat = capacity_minus_commitment_fee_msat as u64;
3280-
}
3281-
} else {
3282-
// If the channel is inbound (i.e. counterparty pays the fee), we need to make sure
3283-
// sending a new HTLC won't reduce their balance below our reserve threshold.
3284-
let mut real_dust_limit_success_sat = context.counterparty_dust_limit_satoshis;
3285-
if !context.opt_anchors() {
3286-
real_dust_limit_success_sat += context.feerate_per_kw as u64 * htlc_success_tx_weight(false) / 1000;
3287-
}
3288-
3289-
let htlc_above_dust = HTLCCandidate::new(real_dust_limit_success_sat * 1000, HTLCInitiator::LocalOffered);
3290-
let max_reserved_commit_tx_fee_msat = context.next_remote_commit_tx_fee_msat(htlc_above_dust, None);
3291-
3292-
let holder_selected_chan_reserve_msat = context.holder_selected_channel_reserve_satoshis * 1000;
3293-
let remote_balance_msat = (context.channel_value_satoshis * 1000 - context.value_to_self_msat)
3294-
.saturating_sub(inbound_stats.pending_htlcs_value_msat);
3295-
3296-
if remote_balance_msat < max_reserved_commit_tx_fee_msat + holder_selected_chan_reserve_msat {
3297-
// If another HTLC's fee would reduce the remote's balance below the reserve limit
3298-
// we've selected for them, we can only send dust HTLCs.
3299-
available_capacity_msat = cmp::min(available_capacity_msat, real_dust_limit_success_sat * 1000 - 1);
3300-
}
3301-
}
3302-
3303-
let mut next_outbound_htlc_minimum_msat = context.counterparty_htlc_minimum_msat;
3304-
3305-
// If we get close to our maximum dust exposure, we end up in a situation where we can send
3306-
// between zero and the remaining dust exposure limit remaining OR above the dust limit.
3307-
// Because we cannot express this as a simple min/max, we prefer to tell the user they can
3308-
// send above the dust limit (as the router can always overpay to meet the dust limit).
3309-
let mut remaining_msat_below_dust_exposure_limit = None;
3310-
let mut dust_exposure_dust_limit_msat = 0;
3311-
3312-
let (htlc_success_dust_limit, htlc_timeout_dust_limit) = if context.opt_anchors() {
3313-
(context.counterparty_dust_limit_satoshis, context.holder_dust_limit_satoshis)
3314-
} else {
3315-
let dust_buffer_feerate = context.get_dust_buffer_feerate(None) as u64;
3316-
(context.counterparty_dust_limit_satoshis + dust_buffer_feerate * htlc_success_tx_weight(false) / 1000,
3317-
context.holder_dust_limit_satoshis + dust_buffer_feerate * htlc_timeout_tx_weight(false) / 1000)
3318-
};
3319-
let on_counterparty_dust_htlc_exposure_msat = inbound_stats.on_counterparty_tx_dust_exposure_msat + outbound_stats.on_counterparty_tx_dust_exposure_msat;
3320-
if on_counterparty_dust_htlc_exposure_msat as i64 + htlc_success_dust_limit as i64 * 1000 - 1 > context.get_max_dust_htlc_exposure_msat() as i64 {
3321-
remaining_msat_below_dust_exposure_limit =
3322-
Some(context.get_max_dust_htlc_exposure_msat().saturating_sub(on_counterparty_dust_htlc_exposure_msat));
3323-
dust_exposure_dust_limit_msat = cmp::max(dust_exposure_dust_limit_msat, htlc_success_dust_limit * 1000);
3324-
}
3325-
3326-
let on_holder_dust_htlc_exposure_msat = inbound_stats.on_holder_tx_dust_exposure_msat + outbound_stats.on_holder_tx_dust_exposure_msat;
3327-
if on_holder_dust_htlc_exposure_msat as i64 + htlc_timeout_dust_limit as i64 * 1000 - 1 > context.get_max_dust_htlc_exposure_msat() as i64 {
3328-
remaining_msat_below_dust_exposure_limit = Some(cmp::min(
3329-
remaining_msat_below_dust_exposure_limit.unwrap_or(u64::max_value()),
3330-
context.get_max_dust_htlc_exposure_msat().saturating_sub(on_holder_dust_htlc_exposure_msat)));
3331-
dust_exposure_dust_limit_msat = cmp::max(dust_exposure_dust_limit_msat, htlc_timeout_dust_limit * 1000);
3332-
}
3333-
3334-
if let Some(remaining_limit_msat) = remaining_msat_below_dust_exposure_limit {
3335-
if available_capacity_msat < dust_exposure_dust_limit_msat {
3336-
available_capacity_msat = cmp::min(available_capacity_msat, remaining_limit_msat);
3337-
} else {
3338-
next_outbound_htlc_minimum_msat = cmp::max(next_outbound_htlc_minimum_msat, dust_exposure_dust_limit_msat);
3339-
}
3340-
}
3341-
3342-
available_capacity_msat = cmp::min(available_capacity_msat,
3343-
context.counterparty_max_htlc_value_in_flight_msat - outbound_stats.pending_htlcs_value_msat);
3344-
3345-
if outbound_stats.pending_htlcs + 1 > context.counterparty_max_accepted_htlcs as u32 {
3346-
available_capacity_msat = 0;
3347-
}
3348-
3349-
AvailableBalances {
3350-
inbound_capacity_msat: cmp::max(context.channel_value_satoshis as i64 * 1000
3351-
- context.value_to_self_msat as i64
3352-
- context.get_inbound_pending_htlc_stats(None).pending_htlcs_value_msat as i64
3353-
- context.holder_selected_channel_reserve_satoshis as i64 * 1000,
3354-
0) as u64,
3355-
outbound_capacity_msat,
3356-
next_outbound_htlc_limit_msat: available_capacity_msat,
3357-
next_outbound_htlc_minimum_msat,
3358-
balance_msat,
3359-
}
3360-
}
3361-
33623362
pub fn update_add_htlc<F, L: Deref>(&mut self, msg: &msgs::UpdateAddHTLC, mut pending_forward_status: PendingHTLCStatus, create_pending_htlc_status: F, logger: &L) -> Result<(), ChannelError>
33633363
where F: for<'a> Fn(&'a Self, PendingHTLCStatus, u16) -> PendingHTLCStatus, L::Target: Logger {
33643364
// We can't accept HTLCs sent after we've sent a shutdown.
@@ -6048,7 +6048,7 @@ impl<Signer: WriteableEcdsaChannelSigner> Channel<Signer> {
60486048
return Err(ChannelError::Ignore("Cannot send 0-msat HTLC".to_owned()));
60496049
}
60506050

6051-
let available_balances = self.get_available_balances();
6051+
let available_balances = self.context.get_available_balances();
60526052
if amount_msat < available_balances.next_outbound_htlc_minimum_msat {
60536053
return Err(ChannelError::Ignore(format!("Cannot send less than our next-HTLC minimum - {} msat",
60546054
available_balances.next_outbound_htlc_minimum_msat)));

lightning/src/ln/channelmanager.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1469,7 +1469,7 @@ impl ChannelDetails {
14691469
fn from_channel<Signer: WriteableEcdsaChannelSigner>(channel: &Channel<Signer>,
14701470
best_block_height: u32, latest_features: InitFeatures) -> Self {
14711471

1472-
let balance = channel.get_available_balances();
1472+
let balance = channel.context.get_available_balances();
14731473
let (to_remote_reserve_satoshis, to_self_reserve_satoshis) =
14741474
channel.context.get_holder_counterparty_selected_channel_reserve_satoshis();
14751475
ChannelDetails {

0 commit comments

Comments
 (0)