@@ -126,17 +126,11 @@ pub(crate) struct ChannelConstraints {
126
126
127
127
pub ( crate ) trait TxBuilder {
128
128
fn get_available_balances (
129
- & self ,
130
- is_outbound_from_holder : bool ,
131
- channel_value_satoshis : u64 ,
132
- value_to_holder_msat : u64 ,
133
- pending_htlcs : & [ HTLCAmountDirection ] ,
134
- feerate_per_kw : u32 ,
135
- dust_exposure_limiting_feerate : Option < u32 > ,
136
- max_dust_htlc_exposure_msat : u64 ,
129
+ & self , is_outbound_from_holder : bool , channel_value_satoshis : u64 ,
130
+ value_to_holder_msat : u64 , pending_htlcs : & [ HTLCAmountDirection ] , feerate_per_kw : u32 ,
131
+ dust_exposure_limiting_feerate : Option < u32 > , max_dust_htlc_exposure_msat : u64 ,
137
132
holder_channel_constraints : ChannelConstraints ,
138
- counterparty_channel_constraints : ChannelConstraints ,
139
- channel_type : & ChannelTypeFeatures ,
133
+ counterparty_channel_constraints : ChannelConstraints , channel_type : & ChannelTypeFeatures ,
140
134
) -> crate :: ln:: channel:: AvailableBalances ;
141
135
fn get_next_commitment_stats (
142
136
& self , local : bool , is_outbound_from_holder : bool , channel_value_satoshis : u64 ,
@@ -159,36 +153,60 @@ pub(crate) struct SpecTxBuilder {}
159
153
160
154
impl TxBuilder for SpecTxBuilder {
161
155
fn get_available_balances (
162
- & self ,
163
- is_outbound_from_holder : bool ,
164
- channel_value_satoshis : u64 ,
165
- value_to_holder_msat : u64 ,
166
- pending_htlcs : & [ HTLCAmountDirection ] ,
167
- feerate_per_kw : u32 ,
168
- dust_exposure_limiting_feerate : Option < u32 > ,
169
- max_dust_htlc_exposure_msat : u64 ,
156
+ & self , is_outbound_from_holder : bool , channel_value_satoshis : u64 ,
157
+ value_to_holder_msat : u64 , pending_htlcs : & [ HTLCAmountDirection ] , feerate_per_kw : u32 ,
158
+ dust_exposure_limiting_feerate : Option < u32 > , max_dust_htlc_exposure_msat : u64 ,
170
159
holder_channel_constraints : ChannelConstraints ,
171
- counterparty_channel_constraints : ChannelConstraints ,
172
- channel_type : & ChannelTypeFeatures ,
160
+ counterparty_channel_constraints : ChannelConstraints , channel_type : & ChannelTypeFeatures ,
173
161
) -> crate :: ln:: channel:: AvailableBalances {
174
- let fee_spike_buffer_htlc = if channel_type. supports_anchor_zero_fee_commitments ( ) {
175
- 0
176
- } else {
177
- 1
178
- } ;
179
-
180
- let local_stats_max_fee = SpecTxBuilder { } . get_next_commitment_stats ( true , is_outbound_from_holder, channel_value_satoshis, value_to_holder_msat, pending_htlcs, fee_spike_buffer_htlc + 1 , feerate_per_kw, dust_exposure_limiting_feerate, holder_channel_constraints. dust_limit_satoshis , channel_type) ;
181
- let local_stats_min_fee = SpecTxBuilder { } . get_next_commitment_stats ( true , is_outbound_from_holder, channel_value_satoshis, value_to_holder_msat, pending_htlcs, fee_spike_buffer_htlc, feerate_per_kw, dust_exposure_limiting_feerate, holder_channel_constraints. dust_limit_satoshis , channel_type) ;
182
- let remote_stats = SpecTxBuilder { } . get_next_commitment_stats ( false , is_outbound_from_holder, channel_value_satoshis, value_to_holder_msat, pending_htlcs, 1 , feerate_per_kw, dust_exposure_limiting_feerate, counterparty_channel_constraints. dust_limit_satoshis , channel_type) ;
162
+ let fee_spike_buffer_htlc =
163
+ if channel_type. supports_anchor_zero_fee_commitments ( ) { 0 } else { 1 } ;
164
+
165
+ let local_stats_max_fee = SpecTxBuilder { } . get_next_commitment_stats (
166
+ true ,
167
+ is_outbound_from_holder,
168
+ channel_value_satoshis,
169
+ value_to_holder_msat,
170
+ pending_htlcs,
171
+ fee_spike_buffer_htlc + 1 ,
172
+ feerate_per_kw,
173
+ dust_exposure_limiting_feerate,
174
+ holder_channel_constraints. dust_limit_satoshis ,
175
+ channel_type,
176
+ ) ;
177
+ let local_stats_min_fee = SpecTxBuilder { } . get_next_commitment_stats (
178
+ true ,
179
+ is_outbound_from_holder,
180
+ channel_value_satoshis,
181
+ value_to_holder_msat,
182
+ pending_htlcs,
183
+ fee_spike_buffer_htlc,
184
+ feerate_per_kw,
185
+ dust_exposure_limiting_feerate,
186
+ holder_channel_constraints. dust_limit_satoshis ,
187
+ channel_type,
188
+ ) ;
189
+ let remote_stats = SpecTxBuilder { } . get_next_commitment_stats (
190
+ false ,
191
+ is_outbound_from_holder,
192
+ channel_value_satoshis,
193
+ value_to_holder_msat,
194
+ pending_htlcs,
195
+ 1 ,
196
+ feerate_per_kw,
197
+ dust_exposure_limiting_feerate,
198
+ counterparty_channel_constraints. dust_limit_satoshis ,
199
+ channel_type,
200
+ ) ;
183
201
184
- let outbound_capacity_msat = local_stats_max_fee. holder_balance_before_fee_msat . unwrap_or ( 0 )
185
- . saturating_sub (
186
- holder_channel_constraints. channel_reserve_satoshis * 1000 ) ;
202
+ let outbound_capacity_msat = local_stats_max_fee
203
+ . holder_balance_before_fee_msat
204
+ . unwrap_or ( 0 )
205
+ . saturating_sub ( holder_channel_constraints. channel_reserve_satoshis * 1000 ) ;
187
206
188
207
let mut available_capacity_msat = outbound_capacity_msat;
189
- let ( real_htlc_success_tx_fee_sat, real_htlc_timeout_tx_fee_sat) = second_stage_tx_fees_sat (
190
- channel_type, feerate_per_kw
191
- ) ;
208
+ let ( real_htlc_success_tx_fee_sat, real_htlc_timeout_tx_fee_sat) =
209
+ second_stage_tx_fees_sat ( channel_type, feerate_per_kw) ;
192
210
193
211
if is_outbound_from_holder {
194
212
// We should mind channel commit tx fee when computing how much of the available capacity
@@ -199,40 +217,54 @@ impl TxBuilder for SpecTxBuilder {
199
217
// dependency.
200
218
// This complicates the computation around dust-values, up to the one-htlc-value.
201
219
202
- let real_dust_limit_timeout_sat = real_htlc_timeout_tx_fee_sat + holder_channel_constraints. dust_limit_satoshis ;
220
+ let real_dust_limit_timeout_sat =
221
+ real_htlc_timeout_tx_fee_sat + holder_channel_constraints. dust_limit_satoshis ;
203
222
let mut max_reserved_commit_tx_fee_msat = local_stats_max_fee. commit_tx_fee_sat * 1000 ;
204
223
let mut min_reserved_commit_tx_fee_msat = local_stats_min_fee. commit_tx_fee_sat * 1000 ;
205
224
206
225
if !channel_type. supports_anchors_zero_fee_htlc_tx ( ) {
207
- max_reserved_commit_tx_fee_msat *= crate :: ln:: channel:: FEE_SPIKE_BUFFER_FEE_INCREASE_MULTIPLE ;
208
- min_reserved_commit_tx_fee_msat *= crate :: ln:: channel:: FEE_SPIKE_BUFFER_FEE_INCREASE_MULTIPLE ;
226
+ max_reserved_commit_tx_fee_msat *=
227
+ crate :: ln:: channel:: FEE_SPIKE_BUFFER_FEE_INCREASE_MULTIPLE ;
228
+ min_reserved_commit_tx_fee_msat *=
229
+ crate :: ln:: channel:: FEE_SPIKE_BUFFER_FEE_INCREASE_MULTIPLE ;
209
230
}
210
231
211
232
// We will first subtract the fee as if we were above-dust. Then, if the resulting
212
233
// value ends up being below dust, we have this fee available again. In that case,
213
234
// match the value to right-below-dust.
214
- let capacity_minus_max_commitment_fee_msat = available_capacity_msat. saturating_sub ( max_reserved_commit_tx_fee_msat) ;
235
+ let capacity_minus_max_commitment_fee_msat =
236
+ available_capacity_msat. saturating_sub ( max_reserved_commit_tx_fee_msat) ;
215
237
if capacity_minus_max_commitment_fee_msat < real_dust_limit_timeout_sat * 1000 {
216
- let capacity_minus_min_commitment_fee_msat = available_capacity_msat. saturating_sub ( min_reserved_commit_tx_fee_msat) ;
217
- available_capacity_msat = cmp:: min ( real_dust_limit_timeout_sat * 1000 - 1 , capacity_minus_min_commitment_fee_msat) ;
238
+ let capacity_minus_min_commitment_fee_msat =
239
+ available_capacity_msat. saturating_sub ( min_reserved_commit_tx_fee_msat) ;
240
+ available_capacity_msat = cmp:: min (
241
+ real_dust_limit_timeout_sat * 1000 - 1 ,
242
+ capacity_minus_min_commitment_fee_msat,
243
+ ) ;
218
244
} else {
219
245
available_capacity_msat = capacity_minus_max_commitment_fee_msat;
220
246
}
221
247
} else {
222
248
// If the channel is inbound (i.e. counterparty pays the fee), we need to make sure
223
249
// sending a new HTLC won't reduce their balance below our reserve threshold.
224
- let real_dust_limit_success_sat = real_htlc_success_tx_fee_sat + counterparty_channel_constraints. dust_limit_satoshis ;
250
+ let real_dust_limit_success_sat =
251
+ real_htlc_success_tx_fee_sat + counterparty_channel_constraints. dust_limit_satoshis ;
225
252
let max_reserved_commit_tx_fee_msat = remote_stats. commit_tx_fee_sat * 1000 ;
226
253
227
- let holder_selected_chan_reserve_msat = counterparty_channel_constraints. channel_reserve_satoshis * 1000 ;
228
- if remote_stats. counterparty_balance_before_fee_msat . unwrap_or ( 0 ) < max_reserved_commit_tx_fee_msat + holder_selected_chan_reserve_msat {
254
+ let holder_selected_chan_reserve_msat =
255
+ counterparty_channel_constraints. channel_reserve_satoshis * 1000 ;
256
+ if remote_stats. counterparty_balance_before_fee_msat . unwrap_or ( 0 )
257
+ < max_reserved_commit_tx_fee_msat + holder_selected_chan_reserve_msat
258
+ {
229
259
// If another HTLC's fee would reduce the remote's balance below the reserve limit
230
260
// we've selected for them, we can only send dust HTLCs.
231
- available_capacity_msat = cmp:: min ( available_capacity_msat, real_dust_limit_success_sat * 1000 - 1 ) ;
261
+ available_capacity_msat =
262
+ cmp:: min ( available_capacity_msat, real_dust_limit_success_sat * 1000 - 1 ) ;
232
263
}
233
264
}
234
265
235
- let mut next_outbound_htlc_minimum_msat = counterparty_channel_constraints. htlc_minimum_msat ;
266
+ let mut next_outbound_htlc_minimum_msat =
267
+ counterparty_channel_constraints. htlc_minimum_msat ;
236
268
237
269
// If we get close to our maximum dust exposure, we end up in a situation where we can send
238
270
// between zero and the remaining dust exposure limit remaining OR above the dust limit.
@@ -242,52 +274,77 @@ impl TxBuilder for SpecTxBuilder {
242
274
let mut dust_exposure_dust_limit_msat = 0 ;
243
275
244
276
let dust_buffer_feerate = get_dust_buffer_feerate ( feerate_per_kw) ;
245
- let ( buffer_htlc_success_tx_fee_sat, buffer_htlc_timeout_tx_fee_sat) = second_stage_tx_fees_sat (
246
- channel_type, dust_buffer_feerate,
247
- ) ;
248
- let buffer_dust_limit_success_sat = buffer_htlc_success_tx_fee_sat + counterparty_channel_constraints. dust_limit_satoshis ;
249
- let buffer_dust_limit_timeout_sat = buffer_htlc_timeout_tx_fee_sat + holder_channel_constraints. dust_limit_satoshis ;
250
-
251
- if let Some ( extra_htlc_dust_exposure) = remote_stats. extra_nondust_htlc_on_counterparty_tx_dust_exposure_msat {
277
+ let ( buffer_htlc_success_tx_fee_sat, buffer_htlc_timeout_tx_fee_sat) =
278
+ second_stage_tx_fees_sat ( channel_type, dust_buffer_feerate) ;
279
+ let buffer_dust_limit_success_sat =
280
+ buffer_htlc_success_tx_fee_sat + counterparty_channel_constraints. dust_limit_satoshis ;
281
+ let buffer_dust_limit_timeout_sat =
282
+ buffer_htlc_timeout_tx_fee_sat + holder_channel_constraints. dust_limit_satoshis ;
283
+
284
+ if let Some ( extra_htlc_dust_exposure) =
285
+ remote_stats. extra_nondust_htlc_on_counterparty_tx_dust_exposure_msat
286
+ {
252
287
if extra_htlc_dust_exposure > max_dust_htlc_exposure_msat {
253
288
// If adding an extra HTLC would put us over the dust limit in total fees, we cannot
254
289
// send any non-dust HTLCs.
255
- available_capacity_msat = cmp:: min ( available_capacity_msat, buffer_dust_limit_success_sat * 1000 ) ;
290
+ available_capacity_msat =
291
+ cmp:: min ( available_capacity_msat, buffer_dust_limit_success_sat * 1000 ) ;
256
292
}
257
293
}
258
294
259
- if remote_stats. dust_exposure_msat . saturating_add ( buffer_dust_limit_success_sat * 1000 ) > max_dust_htlc_exposure_msat. saturating_add ( 1 ) {
295
+ if remote_stats. dust_exposure_msat . saturating_add ( buffer_dust_limit_success_sat * 1000 )
296
+ > max_dust_htlc_exposure_msat. saturating_add ( 1 )
297
+ {
260
298
// Note that we don't use the `counterparty_tx_dust_exposure` (with
261
299
// `htlc_dust_exposure_msat`) here as it only applies to non-dust HTLCs.
262
300
remaining_msat_below_dust_exposure_limit =
263
301
Some ( max_dust_htlc_exposure_msat. saturating_sub ( remote_stats. dust_exposure_msat ) ) ;
264
- dust_exposure_dust_limit_msat = cmp:: max ( dust_exposure_dust_limit_msat, buffer_dust_limit_success_sat * 1000 ) ;
302
+ dust_exposure_dust_limit_msat =
303
+ cmp:: max ( dust_exposure_dust_limit_msat, buffer_dust_limit_success_sat * 1000 ) ;
265
304
}
266
305
267
- if local_stats_max_fee. dust_exposure_msat as i64 + buffer_dust_limit_timeout_sat as i64 * 1000 - 1 > max_dust_htlc_exposure_msat. try_into ( ) . unwrap_or ( i64:: max_value ( ) ) {
306
+ if local_stats_max_fee. dust_exposure_msat as i64
307
+ + buffer_dust_limit_timeout_sat as i64 * 1000
308
+ - 1 > max_dust_htlc_exposure_msat. try_into ( ) . unwrap_or ( i64:: max_value ( ) )
309
+ {
268
310
remaining_msat_below_dust_exposure_limit = Some ( cmp:: min (
269
311
remaining_msat_below_dust_exposure_limit. unwrap_or ( u64:: max_value ( ) ) ,
270
- max_dust_htlc_exposure_msat. saturating_sub ( local_stats_max_fee. dust_exposure_msat ) ) ) ;
271
- dust_exposure_dust_limit_msat = cmp:: max ( dust_exposure_dust_limit_msat, buffer_dust_limit_timeout_sat * 1000 ) ;
312
+ max_dust_htlc_exposure_msat. saturating_sub ( local_stats_max_fee. dust_exposure_msat ) ,
313
+ ) ) ;
314
+ dust_exposure_dust_limit_msat =
315
+ cmp:: max ( dust_exposure_dust_limit_msat, buffer_dust_limit_timeout_sat * 1000 ) ;
272
316
}
273
317
274
318
if let Some ( remaining_limit_msat) = remaining_msat_below_dust_exposure_limit {
275
319
if available_capacity_msat < dust_exposure_dust_limit_msat {
276
320
available_capacity_msat = cmp:: min ( available_capacity_msat, remaining_limit_msat) ;
277
321
} else {
278
- next_outbound_htlc_minimum_msat = cmp:: max ( next_outbound_htlc_minimum_msat, dust_exposure_dust_limit_msat) ;
322
+ next_outbound_htlc_minimum_msat =
323
+ cmp:: max ( next_outbound_htlc_minimum_msat, dust_exposure_dust_limit_msat) ;
279
324
}
280
325
}
281
326
282
- available_capacity_msat = cmp:: min ( available_capacity_msat,
283
- counterparty_channel_constraints. max_htlc_value_in_flight_msat - pending_htlcs. iter ( ) . filter ( |htlc| htlc. outbound ) . map ( |htlc| htlc. amount_msat ) . sum :: < u64 > ( ) ) ;
327
+ available_capacity_msat = cmp:: min (
328
+ available_capacity_msat,
329
+ counterparty_channel_constraints. max_htlc_value_in_flight_msat
330
+ - pending_htlcs
331
+ . iter ( )
332
+ . filter ( |htlc| htlc. outbound )
333
+ . map ( |htlc| htlc. amount_msat )
334
+ . sum :: < u64 > ( ) ,
335
+ ) ;
284
336
285
- if pending_htlcs. iter ( ) . filter ( |htlc| htlc. outbound ) . count ( ) + 1 > counterparty_channel_constraints. max_accepted_htlcs as usize {
337
+ if pending_htlcs. iter ( ) . filter ( |htlc| htlc. outbound ) . count ( ) + 1
338
+ > counterparty_channel_constraints. max_accepted_htlcs as usize
339
+ {
286
340
available_capacity_msat = 0 ;
287
341
}
288
342
289
343
crate :: ln:: channel:: AvailableBalances {
290
- inbound_capacity_msat : remote_stats. counterparty_balance_before_fee_msat . unwrap_or ( 0 ) . saturating_sub ( counterparty_channel_constraints. channel_reserve_satoshis * 1000 ) ,
344
+ inbound_capacity_msat : remote_stats
345
+ . counterparty_balance_before_fee_msat
346
+ . unwrap_or ( 0 )
347
+ . saturating_sub ( counterparty_channel_constraints. channel_reserve_satoshis * 1000 ) ,
291
348
outbound_capacity_msat,
292
349
next_outbound_htlc_limit_msat : available_capacity_msat,
293
350
next_outbound_htlc_minimum_msat,
0 commit comments