Skip to content

Commit 29e755b

Browse files
author
Antoine Riard
committed
Modify pending inbound/outbound getters to access dust balances
1 parent 53b6823 commit 29e755b

File tree

1 file changed

+79
-25
lines changed

1 file changed

+79
-25
lines changed

lightning/src/ln/channel.rs

Lines changed: 79 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -274,6 +274,14 @@ enum HTLCInitiator {
274274
RemoteOffered,
275275
}
276276

277+
/// An enum gathering stats on pending HTLCs, either inbound or outbound side.
278+
struct HTLCStats {
279+
pending_htlcs: u32,
280+
pending_htlcs_value_msat: u64,
281+
on_counterparty_tx_dust_exposure_msat: u64,
282+
on_holder_tx_dust_exposure_msat: u64,
283+
}
284+
277285
/// Used when calculating whether we or the remote can afford an additional HTLC.
278286
struct HTLCCandidate {
279287
amount_msat: u64,
@@ -1816,32 +1824,63 @@ impl<Signer: Sign> Channel<Signer> {
18161824
Ok(())
18171825
}
18181826

1819-
/// Returns (inbound_htlc_count, htlc_inbound_value_msat)
1820-
fn get_inbound_pending_htlc_stats(&self) -> (u32, u64) {
1821-
let mut htlc_inbound_value_msat = 0;
1827+
/// Returns a HTLCStats about inbound pending htlcs
1828+
fn get_inbound_pending_htlc_stats(&self) -> HTLCStats {
1829+
let mut stats = HTLCStats {
1830+
pending_htlcs: self.pending_inbound_htlcs.len() as u32,
1831+
pending_htlcs_value_msat: 0,
1832+
on_counterparty_tx_dust_exposure_msat: 0,
1833+
on_holder_tx_dust_exposure_msat: 0,
1834+
};
1835+
1836+
let counterparty_dust_limit_timeout_sat = (self.get_dust_buffer_feerate() as u64 * HTLC_TIMEOUT_TX_WEIGHT / 1000) + self.counterparty_dust_limit_satoshis;
1837+
let holder_dust_limit_success_sat = (self.get_dust_buffer_feerate() as u64 * HTLC_SUCCESS_TX_WEIGHT / 1000) + self.holder_dust_limit_satoshis;
18221838
for ref htlc in self.pending_inbound_htlcs.iter() {
1823-
htlc_inbound_value_msat += htlc.amount_msat;
1839+
stats.pending_htlcs_value_msat += htlc.amount_msat;
1840+
if htlc.amount_msat / 1000 < counterparty_dust_limit_timeout_sat {
1841+
stats.on_counterparty_tx_dust_exposure_msat += htlc.amount_msat;
1842+
}
1843+
if htlc.amount_msat / 1000 < holder_dust_limit_success_sat {
1844+
stats.on_holder_tx_dust_exposure_msat += htlc.amount_msat;
1845+
}
18241846
}
1825-
(self.pending_inbound_htlcs.len() as u32, htlc_inbound_value_msat)
1847+
stats
18261848
}
18271849

1828-
/// Returns (outbound_htlc_count, htlc_outbound_value_msat) *including* pending adds in our
1829-
/// holding cell.
1830-
fn get_outbound_pending_htlc_stats(&self) -> (u32, u64) {
1831-
let mut htlc_outbound_value_msat = 0;
1850+
/// Returns a HTLCStats about pending outbound htlcs, *including* pending adds in our holding cell.
1851+
fn get_outbound_pending_htlc_stats(&self) -> HTLCStats {
1852+
let mut stats = HTLCStats {
1853+
pending_htlcs: self.pending_outbound_htlcs.len() as u32,
1854+
pending_htlcs_value_msat: 0,
1855+
on_counterparty_tx_dust_exposure_msat: 0,
1856+
on_holder_tx_dust_exposure_msat: 0,
1857+
};
1858+
1859+
let counterparty_dust_limit_success_sat = (self.get_dust_buffer_feerate() as u64 * HTLC_SUCCESS_TX_WEIGHT / 1000) + self.counterparty_dust_limit_satoshis;
1860+
let holder_dust_limit_timeout_sat = (self.get_dust_buffer_feerate() as u64 * HTLC_TIMEOUT_TX_WEIGHT / 1000) + self.holder_dust_limit_satoshis;
18321861
for ref htlc in self.pending_outbound_htlcs.iter() {
1833-
htlc_outbound_value_msat += htlc.amount_msat;
1862+
stats.pending_htlcs_value_msat += htlc.amount_msat;
1863+
if htlc.amount_msat / 1000 < counterparty_dust_limit_success_sat {
1864+
stats.on_counterparty_tx_dust_exposure_msat += htlc.amount_msat;
1865+
}
1866+
if htlc.amount_msat / 1000 < holder_dust_limit_timeout_sat {
1867+
stats.on_holder_tx_dust_exposure_msat += htlc.amount_msat;
1868+
}
18341869
}
18351870

1836-
let mut htlc_outbound_count = self.pending_outbound_htlcs.len();
18371871
for update in self.holding_cell_htlc_updates.iter() {
18381872
if let &HTLCUpdateAwaitingACK::AddHTLC { ref amount_msat, .. } = update {
1839-
htlc_outbound_count += 1;
1840-
htlc_outbound_value_msat += amount_msat;
1873+
stats.pending_htlcs += 1;
1874+
stats.pending_htlcs_value_msat += amount_msat;
1875+
if *amount_msat / 1000 < counterparty_dust_limit_success_sat {
1876+
stats.on_counterparty_tx_dust_exposure_msat += amount_msat;
1877+
}
1878+
if *amount_msat / 1000 < holder_dust_limit_timeout_sat {
1879+
stats.on_holder_tx_dust_exposure_msat += amount_msat;
1880+
}
18411881
}
18421882
}
1843-
1844-
(htlc_outbound_count as u32, htlc_outbound_value_msat)
1883+
stats
18451884
}
18461885

18471886
/// Get the available (ie not including pending HTLCs) inbound and outbound balance in msat.
@@ -1853,11 +1892,11 @@ impl<Signer: Sign> Channel<Signer> {
18531892
(
18541893
cmp::max(self.channel_value_satoshis as i64 * 1000
18551894
- self.value_to_self_msat as i64
1856-
- self.get_inbound_pending_htlc_stats().1 as i64
1895+
- self.get_inbound_pending_htlc_stats().pending_htlcs_value_msat as i64
18571896
- Self::get_holder_selected_channel_reserve_satoshis(self.channel_value_satoshis) as i64 * 1000,
18581897
0) as u64,
18591898
cmp::max(self.value_to_self_msat as i64
1860-
- self.get_outbound_pending_htlc_stats().1 as i64
1899+
- self.get_outbound_pending_htlc_stats().pending_htlcs_value_msat as i64
18611900
- self.counterparty_selected_channel_reserve_satoshis.unwrap_or(0) as i64 * 1000,
18621901
0) as u64
18631902
)
@@ -2069,12 +2108,13 @@ impl<Signer: Sign> Channel<Signer> {
20692108
return Err(ChannelError::Close(format!("Remote side tried to send less than our minimum HTLC value. Lower limit: ({}). Actual: ({})", self.holder_htlc_minimum_msat, msg.amount_msat)));
20702109
}
20712110

2072-
let (inbound_htlc_count, htlc_inbound_value_msat) = self.get_inbound_pending_htlc_stats();
2073-
if inbound_htlc_count + 1 > OUR_MAX_HTLCS as u32 {
2111+
let inbound_stats = self.get_inbound_pending_htlc_stats();
2112+
let outbound_stats = self.get_outbound_pending_htlc_stats();
2113+
if inbound_stats.pending_htlcs + 1 > OUR_MAX_HTLCS as u32 {
20742114
return Err(ChannelError::Close(format!("Remote tried to push more than our max accepted HTLCs ({})", OUR_MAX_HTLCS)));
20752115
}
20762116
let holder_max_htlc_value_in_flight_msat = Channel::<Signer>::get_holder_max_htlc_value_in_flight_msat(self.channel_value_satoshis);
2077-
if htlc_inbound_value_msat + msg.amount_msat > holder_max_htlc_value_in_flight_msat {
2117+
if inbound_stats.pending_htlcs_value_msat + msg.amount_msat > holder_max_htlc_value_in_flight_msat {
20782118
return Err(ChannelError::Close(format!("Remote HTLC add would put them over our max HTLC value ({})", holder_max_htlc_value_in_flight_msat)));
20792119
}
20802120
// Check holder_selected_channel_reserve_satoshis (we're getting paid, so they have to at least meet
@@ -2099,7 +2139,7 @@ impl<Signer: Sign> Channel<Signer> {
20992139
}
21002140

21012141
let pending_value_to_self_msat =
2102-
self.value_to_self_msat + htlc_inbound_value_msat - removed_outbound_total_msat;
2142+
self.value_to_self_msat + inbound_stats.pending_htlcs_value_msat - removed_outbound_total_msat;
21032143
let pending_remote_value_msat =
21042144
self.channel_value_satoshis * 1000 - pending_value_to_self_msat;
21052145
if pending_remote_value_msat < msg.amount_msat {
@@ -3502,11 +3542,24 @@ impl<Signer: Sign> Channel<Signer> {
35023542
cmp::max(self.config.cltv_expiry_delta, MIN_CLTV_EXPIRY_DELTA)
35033543
}
35043544

3545+
pub fn get_max_dust_htlc_exposure_msat(&self) -> u64 {
3546+
self.config.max_dust_htlc_exposure_msat
3547+
}
3548+
35053549
#[cfg(test)]
35063550
pub fn get_feerate(&self) -> u32 {
35073551
self.feerate_per_kw
35083552
}
35093553

3554+
pub fn get_dust_buffer_feerate(&self) -> u32 {
3555+
// When calculating our exposure to dust HTLCs, we assume that the channel feerate
3556+
// may, at any point, increase by at least 10 sat/vB (i.e 2530 sat/kWU) or 25%,
3557+
// whichever is higher. This ensures that we aren't suddenly exposed to significantly
3558+
// more dust balance if the feerate increases when we have several HTLCs pending
3559+
// which are near the dust limit.
3560+
cmp::max(2530, self.feerate_per_kw * 1250 / 1000)
3561+
}
3562+
35103563
pub fn get_cur_holder_commitment_transaction_number(&self) -> u64 {
35113564
self.cur_holder_commitment_transaction_number + 1
35123565
}
@@ -4145,12 +4198,13 @@ impl<Signer: Sign> Channel<Signer> {
41454198
return Err(ChannelError::Ignore("Cannot send an HTLC while disconnected from channel counterparty".to_owned()));
41464199
}
41474200

4148-
let (outbound_htlc_count, htlc_outbound_value_msat) = self.get_outbound_pending_htlc_stats();
4149-
if outbound_htlc_count + 1 > self.counterparty_max_accepted_htlcs as u32 {
4201+
let inbound_stats = self.get_inbound_pending_htlc_stats();
4202+
let outbound_stats = self.get_outbound_pending_htlc_stats();
4203+
if outbound_stats.pending_htlcs + 1 > self.counterparty_max_accepted_htlcs as u32 {
41504204
return Err(ChannelError::Ignore(format!("Cannot push more than their max accepted HTLCs ({})", self.counterparty_max_accepted_htlcs)));
41514205
}
41524206
// Check their_max_htlc_value_in_flight_msat
4153-
if htlc_outbound_value_msat + amount_msat > self.counterparty_max_htlc_value_in_flight_msat {
4207+
if outbound_stats.pending_htlcs_value_msat + amount_msat > self.counterparty_max_htlc_value_in_flight_msat {
41544208
return Err(ChannelError::Ignore(format!("Cannot send value that would put us over the max HTLC value in flight our peer will accept ({})", self.counterparty_max_htlc_value_in_flight_msat)));
41554209
}
41564210

@@ -4165,7 +4219,7 @@ impl<Signer: Sign> Channel<Signer> {
41654219
}
41664220
}
41674221

4168-
let pending_value_to_self_msat = self.value_to_self_msat - htlc_outbound_value_msat;
4222+
let pending_value_to_self_msat = self.value_to_self_msat - outbound_stats.pending_htlcs_value_msat;
41694223
if pending_value_to_self_msat < amount_msat {
41704224
return Err(ChannelError::Ignore(format!("Cannot send value that would overdraw remaining funds. Amount: {}, pending value to self {}", amount_msat, pending_value_to_self_msat)));
41714225
}

0 commit comments

Comments
 (0)