@@ -1913,16 +1913,16 @@ impl<Signer: Sign> Channel<Signer> {
1913
1913
}
1914
1914
1915
1915
/// Returns a HTLCStats about inbound pending htlcs
1916
- fn get_inbound_pending_htlc_stats ( & self ) -> HTLCStats {
1916
+ fn get_inbound_pending_htlc_stats ( & self , outbound_feerate_update : Option < u32 > ) -> HTLCStats {
1917
1917
let mut stats = HTLCStats {
1918
1918
pending_htlcs : self . pending_inbound_htlcs . len ( ) as u32 ,
1919
1919
pending_htlcs_value_msat : 0 ,
1920
1920
on_counterparty_tx_dust_exposure_msat : 0 ,
1921
1921
on_holder_tx_dust_exposure_msat : 0 ,
1922
1922
} ;
1923
1923
1924
- let counterparty_dust_limit_timeout_sat = ( self . get_dust_buffer_feerate ( ) as u64 * HTLC_TIMEOUT_TX_WEIGHT / 1000 ) + self . counterparty_dust_limit_satoshis ;
1925
- let holder_dust_limit_success_sat = ( self . get_dust_buffer_feerate ( ) as u64 * HTLC_SUCCESS_TX_WEIGHT / 1000 ) + self . holder_dust_limit_satoshis ;
1924
+ let counterparty_dust_limit_timeout_sat = ( self . get_dust_buffer_feerate ( outbound_feerate_update ) as u64 * HTLC_TIMEOUT_TX_WEIGHT / 1000 ) + self . counterparty_dust_limit_satoshis ;
1925
+ let holder_dust_limit_success_sat = ( self . get_dust_buffer_feerate ( outbound_feerate_update ) as u64 * HTLC_SUCCESS_TX_WEIGHT / 1000 ) + self . holder_dust_limit_satoshis ;
1926
1926
for ref htlc in self . pending_inbound_htlcs . iter ( ) {
1927
1927
stats. pending_htlcs_value_msat += htlc. amount_msat ;
1928
1928
if htlc. amount_msat / 1000 < counterparty_dust_limit_timeout_sat {
@@ -1936,16 +1936,16 @@ impl<Signer: Sign> Channel<Signer> {
1936
1936
}
1937
1937
1938
1938
/// Returns a HTLCStats about pending outbound htlcs, *including* pending adds in our holding cell.
1939
- fn get_outbound_pending_htlc_stats ( & self ) -> HTLCStats {
1939
+ fn get_outbound_pending_htlc_stats ( & self , outbound_feerate_update : Option < u32 > ) -> HTLCStats {
1940
1940
let mut stats = HTLCStats {
1941
1941
pending_htlcs : self . pending_outbound_htlcs . len ( ) as u32 ,
1942
1942
pending_htlcs_value_msat : 0 ,
1943
1943
on_counterparty_tx_dust_exposure_msat : 0 ,
1944
1944
on_holder_tx_dust_exposure_msat : 0 ,
1945
1945
} ;
1946
1946
1947
- let counterparty_dust_limit_success_sat = ( self . get_dust_buffer_feerate ( ) as u64 * HTLC_SUCCESS_TX_WEIGHT / 1000 ) + self . counterparty_dust_limit_satoshis ;
1948
- let holder_dust_limit_timeout_sat = ( self . get_dust_buffer_feerate ( ) as u64 * HTLC_TIMEOUT_TX_WEIGHT / 1000 ) + self . holder_dust_limit_satoshis ;
1947
+ let counterparty_dust_limit_success_sat = ( self . get_dust_buffer_feerate ( outbound_feerate_update ) as u64 * HTLC_SUCCESS_TX_WEIGHT / 1000 ) + self . counterparty_dust_limit_satoshis ;
1948
+ let holder_dust_limit_timeout_sat = ( self . get_dust_buffer_feerate ( outbound_feerate_update ) as u64 * HTLC_TIMEOUT_TX_WEIGHT / 1000 ) + self . holder_dust_limit_satoshis ;
1949
1949
for ref htlc in self . pending_outbound_htlcs . iter ( ) {
1950
1950
stats. pending_htlcs_value_msat += htlc. amount_msat ;
1951
1951
if htlc. amount_msat / 1000 < counterparty_dust_limit_success_sat {
@@ -1980,11 +1980,11 @@ impl<Signer: Sign> Channel<Signer> {
1980
1980
(
1981
1981
cmp:: max ( self . channel_value_satoshis as i64 * 1000
1982
1982
- self . value_to_self_msat as i64
1983
- - self . get_inbound_pending_htlc_stats ( ) . pending_htlcs_value_msat as i64
1983
+ - self . get_inbound_pending_htlc_stats ( None ) . pending_htlcs_value_msat as i64
1984
1984
- Self :: get_holder_selected_channel_reserve_satoshis ( self . channel_value_satoshis ) as i64 * 1000 ,
1985
1985
0 ) as u64 ,
1986
1986
cmp:: max ( self . value_to_self_msat as i64
1987
- - self . get_outbound_pending_htlc_stats ( ) . pending_htlcs_value_msat as i64
1987
+ - self . get_outbound_pending_htlc_stats ( None ) . pending_htlcs_value_msat as i64
1988
1988
- self . counterparty_selected_channel_reserve_satoshis . unwrap_or ( 0 ) as i64 * 1000 ,
1989
1989
0 ) as u64
1990
1990
)
@@ -2203,8 +2203,8 @@ impl<Signer: Sign> Channel<Signer> {
2203
2203
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) ) ) ;
2204
2204
}
2205
2205
2206
- let inbound_stats = self . get_inbound_pending_htlc_stats ( ) ;
2207
- let outbound_stats = self . get_outbound_pending_htlc_stats ( ) ;
2206
+ let inbound_stats = self . get_inbound_pending_htlc_stats ( None ) ;
2207
+ let outbound_stats = self . get_outbound_pending_htlc_stats ( None ) ;
2208
2208
if inbound_stats. pending_htlcs + 1 > OUR_MAX_HTLCS as u32 {
2209
2209
return Err ( ChannelError :: Close ( format ! ( "Remote tried to push more than our max accepted HTLCs ({})" , OUR_MAX_HTLCS ) ) ) ;
2210
2210
}
@@ -2233,7 +2233,7 @@ impl<Signer: Sign> Channel<Signer> {
2233
2233
}
2234
2234
}
2235
2235
2236
- let exposure_dust_limit_timeout_sats = ( self . get_dust_buffer_feerate ( ) as u64 * HTLC_TIMEOUT_TX_WEIGHT / 1000 ) + self . counterparty_dust_limit_satoshis ;
2236
+ let exposure_dust_limit_timeout_sats = ( self . get_dust_buffer_feerate ( None ) as u64 * HTLC_TIMEOUT_TX_WEIGHT / 1000 ) + self . counterparty_dust_limit_satoshis ;
2237
2237
if msg. amount_msat / 1000 < exposure_dust_limit_timeout_sats {
2238
2238
let on_counterparty_tx_dust_htlc_exposure_msat = inbound_stats. on_counterparty_tx_dust_exposure_msat + outbound_stats. on_counterparty_tx_dust_exposure_msat + msg. amount_msat ;
2239
2239
if on_counterparty_tx_dust_htlc_exposure_msat > self . get_max_dust_htlc_exposure_msat ( ) {
@@ -2243,7 +2243,7 @@ impl<Signer: Sign> Channel<Signer> {
2243
2243
}
2244
2244
}
2245
2245
2246
- let exposure_dust_limit_success_sats = ( self . get_dust_buffer_feerate ( ) as u64 * HTLC_SUCCESS_TX_WEIGHT / 1000 ) + self . holder_dust_limit_satoshis ;
2246
+ let exposure_dust_limit_success_sats = ( self . get_dust_buffer_feerate ( None ) as u64 * HTLC_SUCCESS_TX_WEIGHT / 1000 ) + self . holder_dust_limit_satoshis ;
2247
2247
if msg. amount_msat / 1000 < exposure_dust_limit_success_sats {
2248
2248
let on_holder_tx_dust_htlc_exposure_msat = inbound_stats. on_holder_tx_dust_exposure_msat + outbound_stats. on_holder_tx_dust_exposure_msat + msg. amount_msat ;
2249
2249
if on_holder_tx_dust_htlc_exposure_msat > self . get_max_dust_htlc_exposure_msat ( ) {
@@ -2977,8 +2977,8 @@ impl<Signer: Sign> Channel<Signer> {
2977
2977
}
2978
2978
2979
2979
// Before proposing a feerate update, check that we can actually afford the new fee.
2980
- let inbound_stats = self . get_inbound_pending_htlc_stats ( ) ;
2981
- let outbound_stats = self . get_outbound_pending_htlc_stats ( ) ;
2980
+ let inbound_stats = self . get_inbound_pending_htlc_stats ( Some ( feerate_per_kw ) ) ;
2981
+ let outbound_stats = self . get_outbound_pending_htlc_stats ( Some ( feerate_per_kw ) ) ;
2982
2982
// In case of a concurrent update_add_htlc proposed by our counterparty, we might
2983
2983
// not have enough balance value remaining to cover the onchain cost of this new
2984
2984
// HTLC weight. If this happens, our counterparty fails the reception of our
@@ -2996,6 +2996,18 @@ impl<Signer: Sign> Channel<Signer> {
2996
2996
return None ;
2997
2997
}
2998
2998
2999
+ if feerate_per_kw > self . get_dust_buffer_feerate ( None ) {
3000
+ // Note, we evaluate pending htlc "preemptive" trimmed-to-dust threshold at the proposed `feerate_per_kw`.
3001
+ let holder_tx_dust_exposure = inbound_stats. on_holder_tx_dust_exposure_msat + outbound_stats. on_holder_tx_dust_exposure_msat ;
3002
+ let counterparty_tx_dust_exposure = inbound_stats. on_counterparty_tx_dust_exposure_msat + outbound_stats. on_counterparty_tx_dust_exposure_msat ;
3003
+ if holder_tx_dust_exposure > self . get_max_dust_htlc_exposure_msat ( ) {
3004
+ return None ;
3005
+ }
3006
+ if counterparty_tx_dust_exposure > self . get_max_dust_htlc_exposure_msat ( ) {
3007
+ return None ;
3008
+ }
3009
+ }
3010
+
2999
3011
if ( self . channel_state & ( ChannelState :: AwaitingRemoteRevoke as u32 | ChannelState :: MonitorUpdateFailed as u32 ) ) != 0 {
3000
3012
self . holding_cell_update_fee = Some ( feerate_per_kw) ;
3001
3013
return None ;
@@ -3163,16 +3175,16 @@ impl<Signer: Sign> Channel<Signer> {
3163
3175
return Err ( ChannelError :: Close ( "Peer sent update_fee when we needed a channel_reestablish" . to_owned ( ) ) ) ;
3164
3176
}
3165
3177
Channel :: < Signer > :: check_remote_fee ( fee_estimator, msg. feerate_per_kw ) ?;
3166
- let feerate_over_dust_buffer = msg. feerate_per_kw > self . get_dust_buffer_feerate ( ) ;
3178
+ let feerate_over_dust_buffer = msg. feerate_per_kw > self . get_dust_buffer_feerate ( None ) ;
3167
3179
3168
3180
self . pending_update_fee = Some ( ( msg. feerate_per_kw , FeeUpdateState :: RemoteAnnounced ) ) ;
3169
3181
self . update_time_counter += 1 ;
3170
3182
// If the feerate has increased over the previous dust buffer (note that
3171
3183
// `get_dust_buffer_feerate` considers the `pending_update_fee` status), check that we
3172
3184
// won't be pushed over our dust exposure limit by the feerate increase.
3173
3185
if feerate_over_dust_buffer {
3174
- let inbound_stats = self . get_inbound_pending_htlc_stats ( ) ;
3175
- let outbound_stats = self . get_outbound_pending_htlc_stats ( ) ;
3186
+ let inbound_stats = self . get_inbound_pending_htlc_stats ( None ) ;
3187
+ let outbound_stats = self . get_outbound_pending_htlc_stats ( None ) ;
3176
3188
let holder_tx_dust_exposure = inbound_stats. on_holder_tx_dust_exposure_msat + outbound_stats. on_holder_tx_dust_exposure_msat ;
3177
3189
let counterparty_tx_dust_exposure = inbound_stats. on_counterparty_tx_dust_exposure_msat + outbound_stats. on_counterparty_tx_dust_exposure_msat ;
3178
3190
if holder_tx_dust_exposure > self . get_max_dust_htlc_exposure_msat ( ) {
@@ -3873,7 +3885,7 @@ impl<Signer: Sign> Channel<Signer> {
3873
3885
self . feerate_per_kw
3874
3886
}
3875
3887
3876
- pub fn get_dust_buffer_feerate ( & self ) -> u32 {
3888
+ pub fn get_dust_buffer_feerate ( & self , outbound_feerate_update : Option < u32 > ) -> u32 {
3877
3889
// When calculating our exposure to dust HTLCs, we assume that the channel feerate
3878
3890
// may, at any point, increase by at least 10 sat/vB (i.e 2530 sat/kWU) or 25%,
3879
3891
// whichever is higher. This ensures that we aren't suddenly exposed to significantly
@@ -3885,6 +3897,9 @@ impl<Signer: Sign> Channel<Signer> {
3885
3897
if let Some ( ( feerate, _) ) = self . pending_update_fee {
3886
3898
feerate_per_kw = cmp:: max ( feerate_per_kw, feerate) ;
3887
3899
}
3900
+ if let Some ( feerate) = outbound_feerate_update {
3901
+ feerate_per_kw = cmp:: max ( feerate_per_kw, feerate) ;
3902
+ }
3888
3903
cmp:: max ( 2530 , feerate_per_kw * 1250 / 1000 )
3889
3904
}
3890
3905
@@ -4542,8 +4557,8 @@ impl<Signer: Sign> Channel<Signer> {
4542
4557
return Err ( ChannelError :: Ignore ( "Cannot send an HTLC while disconnected from channel counterparty" . to_owned ( ) ) ) ;
4543
4558
}
4544
4559
4545
- let inbound_stats = self . get_inbound_pending_htlc_stats ( ) ;
4546
- let outbound_stats = self . get_outbound_pending_htlc_stats ( ) ;
4560
+ let inbound_stats = self . get_inbound_pending_htlc_stats ( None ) ;
4561
+ let outbound_stats = self . get_outbound_pending_htlc_stats ( None ) ;
4547
4562
if outbound_stats. pending_htlcs + 1 > self . counterparty_max_accepted_htlcs as u32 {
4548
4563
return Err ( ChannelError :: Ignore ( format ! ( "Cannot push more than their max accepted HTLCs ({})" , self . counterparty_max_accepted_htlcs) ) ) ;
4549
4564
}
@@ -4563,7 +4578,7 @@ impl<Signer: Sign> Channel<Signer> {
4563
4578
}
4564
4579
}
4565
4580
4566
- let exposure_dust_limit_success_sats = ( self . get_dust_buffer_feerate ( ) as u64 * HTLC_SUCCESS_TX_WEIGHT / 1000 ) + self . counterparty_dust_limit_satoshis ;
4581
+ let exposure_dust_limit_success_sats = ( self . get_dust_buffer_feerate ( None ) as u64 * HTLC_SUCCESS_TX_WEIGHT / 1000 ) + self . counterparty_dust_limit_satoshis ;
4567
4582
if amount_msat / 1000 < exposure_dust_limit_success_sats {
4568
4583
let on_counterparty_dust_htlc_exposure_msat = inbound_stats. on_counterparty_tx_dust_exposure_msat + outbound_stats. on_counterparty_tx_dust_exposure_msat + amount_msat;
4569
4584
if on_counterparty_dust_htlc_exposure_msat > self . get_max_dust_htlc_exposure_msat ( ) {
@@ -4572,7 +4587,7 @@ impl<Signer: Sign> Channel<Signer> {
4572
4587
}
4573
4588
}
4574
4589
4575
- let exposure_dust_limit_timeout_sats = ( self . get_dust_buffer_feerate ( ) as u64 * HTLC_TIMEOUT_TX_WEIGHT / 1000 ) + self . holder_dust_limit_satoshis ;
4590
+ let exposure_dust_limit_timeout_sats = ( self . get_dust_buffer_feerate ( None ) as u64 * HTLC_TIMEOUT_TX_WEIGHT / 1000 ) + self . holder_dust_limit_satoshis ;
4576
4591
if amount_msat / 1000 < exposure_dust_limit_timeout_sats {
4577
4592
let on_holder_dust_htlc_exposure_msat = inbound_stats. on_holder_tx_dust_exposure_msat + outbound_stats. on_holder_tx_dust_exposure_msat + amount_msat;
4578
4593
if on_holder_dust_htlc_exposure_msat > self . get_max_dust_htlc_exposure_msat ( ) {
@@ -4754,13 +4769,13 @@ impl<Signer: Sign> Channel<Signer> {
4754
4769
}
4755
4770
}
4756
4771
}
4757
-
4772
+
4758
4773
if self . is_outbound ( ) {
4759
4774
// Log if we can't afford next remote commitment tx fee at pending outbound feerate update.
4760
4775
if let Some ( pending_feerate) = self . pending_update_fee {
4761
4776
assert_eq ! ( pending_feerate. 1 , FeeUpdateState :: Outbound ) ;
4762
4777
let next_total_fee = Channel :: < Signer > :: commit_tx_fee_sat ( pending_feerate. 0 , self . pending_inbound_htlcs . len ( ) + self . pending_outbound_htlcs . len ( ) ) ;
4763
- let outbound_stats = self . get_outbound_pending_htlc_stats ( ) ;
4778
+ let outbound_stats = self . get_outbound_pending_htlc_stats ( Some ( pending_feerate . 0 ) ) ;
4764
4779
let holder_balance_after_fee_sub_sats = ( self . value_to_self_msat / 1000 ) . checked_sub ( next_total_fee) . map ( |a| a. checked_sub ( outbound_stats. pending_htlcs_value_msat / 1000 ) ) . unwrap_or ( None ) . unwrap_or ( u64:: max_value ( ) ) ;
4765
4780
if holder_balance_after_fee_sub_sats < self . counterparty_selected_channel_reserve_satoshis . unwrap ( ) {
4766
4781
log_trace ! ( logger, "Outbound update_fee HTLC buffer overflow - counterparty should force-close this channel" ) ;
0 commit comments