@@ -3461,9 +3461,11 @@ impl<SP: Deref> ChannelContext<SP> where SP::Target: SignerProvider {
3461
3461
fn build_commitment_transaction<L: Deref>(&self, funding: &FundingScope, commitment_number: u64, per_commitment_point: &PublicKey, local: bool, generated_by_local: bool, logger: &L) -> CommitmentStats
3462
3462
where L::Target: Logger
3463
3463
{
3464
- let mut included_dust_htlcs: Vec<(HTLCOutputInCommitment, Option<&HTLCSource>)> = Vec::new();
3465
3464
let num_htlcs = self.pending_inbound_htlcs.len() + self.pending_outbound_htlcs.len();
3466
- let mut included_non_dust_htlcs: Vec<(HTLCOutputInCommitment, Option<&HTLCSource>)> = Vec::with_capacity(num_htlcs);
3465
+
3466
+ // This will contain all the htlcs included on the commitment transaction due to their state, both dust, and non-dust.
3467
+ // Non-dust htlcs will come first, with their output indices populated, then dust htlcs, with their output indices set to `None`.
3468
+ let mut htlcs_in_tx: Vec<(HTLCOutputInCommitment, Option<&HTLCSource>)> = Vec::with_capacity(num_htlcs);
3467
3469
3468
3470
let broadcaster_dust_limit_satoshis = if local { self.holder_dust_limit_satoshis } else { self.counterparty_dust_limit_satoshis };
3469
3471
let mut remote_htlc_total_msat = 0;
@@ -3501,42 +3503,8 @@ impl<SP: Deref> ChannelContext<SP> where SP::Target: SignerProvider {
3501
3503
}
3502
3504
}
3503
3505
3504
- macro_rules! add_htlc_output {
3505
- ($htlc: expr, $outbound: expr, $source: expr, $state_name: expr) => {
3506
- if $outbound == local { // "offered HTLC output"
3507
- let htlc_in_tx = get_htlc_in_commitment!($htlc, true);
3508
- let htlc_tx_fee = if self.get_channel_type().supports_anchors_zero_fee_htlc_tx() {
3509
- 0
3510
- } else {
3511
- feerate_per_kw as u64 * htlc_timeout_tx_weight(self.get_channel_type()) / 1000
3512
- };
3513
- if $htlc.amount_msat / 1000 >= broadcaster_dust_limit_satoshis + htlc_tx_fee {
3514
- log_trace!(logger, " ...including {} {} HTLC {} (hash {}) with value {}", if $outbound { "outbound" } else { "inbound" }, $state_name, $htlc.htlc_id, &$htlc.payment_hash, $htlc.amount_msat);
3515
- included_non_dust_htlcs.push((htlc_in_tx, $source));
3516
- } else {
3517
- log_trace!(logger, " ...including {} {} dust HTLC {} (hash {}) with value {} due to dust limit", if $outbound { "outbound" } else { "inbound" }, $state_name, $htlc.htlc_id, &$htlc.payment_hash, $htlc.amount_msat);
3518
- included_dust_htlcs.push((htlc_in_tx, $source));
3519
- }
3520
- } else {
3521
- let htlc_in_tx = get_htlc_in_commitment!($htlc, false);
3522
- let htlc_tx_fee = if self.get_channel_type().supports_anchors_zero_fee_htlc_tx() {
3523
- 0
3524
- } else {
3525
- feerate_per_kw as u64 * htlc_success_tx_weight(self.get_channel_type()) / 1000
3526
- };
3527
- if $htlc.amount_msat / 1000 >= broadcaster_dust_limit_satoshis + htlc_tx_fee {
3528
- log_trace!(logger, " ...including {} {} HTLC {} (hash {}) with value {}", if $outbound { "outbound" } else { "inbound" }, $state_name, $htlc.htlc_id, &$htlc.payment_hash, $htlc.amount_msat);
3529
- included_non_dust_htlcs.push((htlc_in_tx, $source));
3530
- } else {
3531
- log_trace!(logger, " ...including {} {} dust HTLC {} (hash {}) with value {}", if $outbound { "outbound" } else { "inbound" }, $state_name, $htlc.htlc_id, &$htlc.payment_hash, $htlc.amount_msat);
3532
- included_dust_htlcs.push((htlc_in_tx, $source));
3533
- }
3534
- }
3535
- }
3536
- }
3537
-
3506
+ // Read the state of htlcs and determine their inclusion in the commitment transaction
3538
3507
let mut inbound_htlc_preimages: Vec<PaymentPreimage> = Vec::new();
3539
-
3540
3508
for ref htlc in self.pending_inbound_htlcs.iter() {
3541
3509
let (include, state_name) = match htlc.state {
3542
3510
InboundHTLCState::RemoteAnnounced(_) => (!generated_by_local, "RemoteAnnounced"),
@@ -3547,8 +3515,9 @@ impl<SP: Deref> ChannelContext<SP> where SP::Target: SignerProvider {
3547
3515
};
3548
3516
3549
3517
if include {
3550
- add_htlc_output!(htlc, false, None, state_name);
3551
- remote_htlc_total_msat += htlc.amount_msat;
3518
+ log_trace!(logger, " ...including inbound HTLC {} (hash {}) with value {} due to state ({})", htlc.htlc_id, &htlc.payment_hash, htlc.amount_msat, state_name);
3519
+ let htlc = get_htlc_in_commitment!(htlc, !local);
3520
+ htlcs_in_tx.push((htlc, None));
3552
3521
} else {
3553
3522
log_trace!(logger, " ...not including inbound HTLC {} (hash {}) with value {} due to state ({})", htlc.htlc_id, &htlc.payment_hash, htlc.amount_msat, state_name);
3554
3523
match &htlc.state {
@@ -3563,7 +3532,6 @@ impl<SP: Deref> ChannelContext<SP> where SP::Target: SignerProvider {
3563
3532
3564
3533
3565
3534
let mut outbound_htlc_preimages: Vec<PaymentPreimage> = Vec::new();
3566
-
3567
3535
for ref htlc in self.pending_outbound_htlcs.iter() {
3568
3536
let (include, state_name) = match htlc.state {
3569
3537
OutboundHTLCState::LocalAnnounced(_) => (generated_by_local, "LocalAnnounced"),
@@ -3585,8 +3553,9 @@ impl<SP: Deref> ChannelContext<SP> where SP::Target: SignerProvider {
3585
3553
}
3586
3554
3587
3555
if include {
3588
- add_htlc_output!(htlc, true, Some(&htlc.source), state_name);
3589
- local_htlc_total_msat += htlc.amount_msat;
3556
+ log_trace!(logger, " ...including outbound HTLC {} (hash {}) with value {} due to state ({})", htlc.htlc_id, &htlc.payment_hash, htlc.amount_msat, state_name);
3557
+ let htlc_in_tx = get_htlc_in_commitment!(htlc, local);
3558
+ htlcs_in_tx.push((htlc_in_tx, Some(&htlc.source)));
3590
3559
} else {
3591
3560
log_trace!(logger, " ...not including outbound HTLC {} (hash {}) with value {} due to state ({})", htlc.htlc_id, &htlc.payment_hash, htlc.amount_msat, state_name);
3592
3561
match htlc.state {
@@ -3600,6 +3569,46 @@ impl<SP: Deref> ChannelContext<SP> where SP::Target: SignerProvider {
3600
3569
}
3601
3570
}
3602
3571
3572
+ // Trim dust htlcs
3573
+ let mut included_non_dust_htlcs: Vec<_> = htlcs_in_tx.iter_mut().map(|(htlc, _)| htlc).collect();
3574
+ included_non_dust_htlcs.retain(|htlc| {
3575
+ let outbound = local == htlc.offered;
3576
+ if outbound {
3577
+ local_htlc_total_msat += htlc.amount_msat;
3578
+ } else {
3579
+ remote_htlc_total_msat += htlc.amount_msat;
3580
+ }
3581
+ let htlc_tx_fee = if self.get_channel_type().supports_anchors_zero_fee_htlc_tx() {
3582
+ 0
3583
+ } else {
3584
+ feerate_per_kw as u64
3585
+ * if htlc.offered {
3586
+ chan_utils::htlc_timeout_tx_weight(self.get_channel_type())
3587
+ } else {
3588
+ chan_utils::htlc_success_tx_weight(self.get_channel_type())
3589
+ } / 1000
3590
+ };
3591
+ if htlc.amount_msat / 1000 >= broadcaster_dust_limit_satoshis + htlc_tx_fee {
3592
+ log_trace!(
3593
+ logger,
3594
+ " ...creating output for {} non-dust HTLC (hash {}) with value {}",
3595
+ if outbound { "outbound" } else { "inbound" },
3596
+ htlc.payment_hash,
3597
+ htlc.amount_msat
3598
+ );
3599
+ true
3600
+ } else {
3601
+ log_trace!(
3602
+ logger,
3603
+ " ...trimming {} HTLC (hash {}) with value {} due to dust limit",
3604
+ if outbound { "outbound" } else { "inbound" },
3605
+ htlc.payment_hash,
3606
+ htlc.amount_msat
3607
+ );
3608
+ false
3609
+ }
3610
+ });
3611
+
3603
3612
// TODO: When MSRV >= 1.66.0, use u64::checked_add_signed
3604
3613
let mut value_to_self_msat = u64::try_from(funding.value_to_self_msat as i64 + value_to_self_msat_offset).unwrap();
3605
3614
// Note that in case they have several just-awaiting-last-RAA fulfills in-progress (ie
@@ -3610,21 +3619,6 @@ impl<SP: Deref> ChannelContext<SP> where SP::Target: SignerProvider {
3610
3619
value_to_self_msat = u64::checked_sub(value_to_self_msat, local_htlc_total_msat).unwrap();
3611
3620
value_to_remote_msat = u64::checked_sub(value_to_remote_msat, remote_htlc_total_msat).unwrap();
3612
3621
3613
- #[cfg(debug_assertions)]
3614
- {
3615
- // Make sure that the to_self/to_remote is always either past the appropriate
3616
- // channel_reserve *or* it is making progress towards it.
3617
- let mut broadcaster_max_commitment_tx_output = if generated_by_local {
3618
- funding.holder_max_commitment_tx_output.lock().unwrap()
3619
- } else {
3620
- funding.counterparty_max_commitment_tx_output.lock().unwrap()
3621
- };
3622
- debug_assert!(broadcaster_max_commitment_tx_output.0 <= value_to_self_msat || value_to_self_msat / 1000 >= funding.counterparty_selected_channel_reserve_satoshis.unwrap());
3623
- broadcaster_max_commitment_tx_output.0 = cmp::max(broadcaster_max_commitment_tx_output.0, value_to_self_msat);
3624
- debug_assert!(broadcaster_max_commitment_tx_output.1 <= value_to_remote_msat || value_to_remote_msat / 1000 >= funding.holder_selected_channel_reserve_satoshis);
3625
- broadcaster_max_commitment_tx_output.1 = cmp::max(broadcaster_max_commitment_tx_output.1, value_to_remote_msat);
3626
- }
3627
-
3628
3622
let total_fee_sat = commit_tx_fee_sat(feerate_per_kw, included_non_dust_htlcs.len(), &funding.channel_transaction_parameters.channel_type_features);
3629
3623
let anchors_val = if funding.channel_transaction_parameters.channel_type_features.supports_anchors_zero_fee_htlc_tx() { ANCHOR_OUTPUT_VALUE_SATOSHI * 2 } else { 0 };
3630
3624
let (value_to_self, value_to_remote) = if funding.is_outbound() {
@@ -3637,14 +3631,16 @@ impl<SP: Deref> ChannelContext<SP> where SP::Target: SignerProvider {
3637
3631
let mut value_to_b = if local { value_to_remote } else { value_to_self };
3638
3632
3639
3633
if value_to_a >= broadcaster_dust_limit_satoshis {
3640
- log_trace!(logger, " ...including {} output with value {}", if local { "to_local" } else { "to_remote" }, value_to_a);
3634
+ log_trace!(logger, " ...creating {} output with value {}", if local { "to_local" } else { "to_remote" }, value_to_a);
3641
3635
} else {
3636
+ log_trace!(logger, " ...trimming {} output with value {} due to dust limit", if local { "to_local" } else { "to_remote" }, value_to_a);
3642
3637
value_to_a = 0;
3643
3638
}
3644
3639
3645
3640
if value_to_b >= broadcaster_dust_limit_satoshis {
3646
- log_trace!(logger, " ...including {} output with value {}", if local { "to_remote" } else { "to_local" }, value_to_b);
3641
+ log_trace!(logger, " ...creating {} output with value {}", if local { "to_remote" } else { "to_local" }, value_to_b);
3647
3642
} else {
3643
+ log_trace!(logger, " ...trimming {} output with value {} due to dust limit", if local { "to_remote" } else { "to_local" }, value_to_b);
3648
3644
value_to_b = 0;
3649
3645
}
3650
3646
@@ -3658,21 +3654,41 @@ impl<SP: Deref> ChannelContext<SP> where SP::Target: SignerProvider {
3658
3654
value_to_a,
3659
3655
value_to_b,
3660
3656
feerate_per_kw,
3661
- included_non_dust_htlcs.iter_mut().map(|(htlc, _)| htlc).collect() ,
3657
+ included_non_dust_htlcs,
3662
3658
&channel_parameters,
3663
3659
&self.secp_ctx,
3664
3660
);
3665
- let mut htlcs_included = included_non_dust_htlcs;
3666
- // The unwrap is safe, because all non-dust HTLCs have been assigned an output index
3667
- htlcs_included.sort_unstable_by_key(|h| h.0.transaction_output_index.unwrap());
3668
- htlcs_included.append(&mut included_dust_htlcs);
3661
+
3662
+ #[cfg(debug_assertions)]
3663
+ {
3664
+ // Make sure that the to_self/to_remote is always either past the appropriate
3665
+ // channel_reserve *or* it is making progress towards it.
3666
+ let mut broadcaster_max_commitment_tx_output = if generated_by_local {
3667
+ funding.holder_max_commitment_tx_output.lock().unwrap()
3668
+ } else {
3669
+ funding.counterparty_max_commitment_tx_output.lock().unwrap()
3670
+ };
3671
+ debug_assert!(broadcaster_max_commitment_tx_output.0 <= value_to_self_msat || value_to_self_msat / 1000 >= funding.counterparty_selected_channel_reserve_satoshis.unwrap());
3672
+ broadcaster_max_commitment_tx_output.0 = cmp::max(broadcaster_max_commitment_tx_output.0, value_to_self_msat);
3673
+ debug_assert!(broadcaster_max_commitment_tx_output.1 <= value_to_remote_msat || value_to_remote_msat / 1000 >= funding.holder_selected_channel_reserve_satoshis);
3674
+ broadcaster_max_commitment_tx_output.1 = cmp::max(broadcaster_max_commitment_tx_output.1, value_to_remote_msat);
3675
+ }
3676
+
3677
+ htlcs_in_tx.sort_unstable_by(|(htlc_a, _), (htlc_b, _)| {
3678
+ match (htlc_a.transaction_output_index, htlc_b.transaction_output_index) {
3679
+ // `None` is smaller than `Some`, but we want `Some` ordered before `None` in the vector
3680
+ (None, Some(_)) => cmp::Ordering::Greater,
3681
+ (Some(_), None) => cmp::Ordering::Less,
3682
+ (l, r) => cmp::Ord::cmp(&l, &r),
3683
+ }
3684
+ });
3669
3685
3670
3686
CommitmentStats {
3671
3687
tx,
3672
3688
feerate_per_kw,
3673
3689
total_fee_sat,
3674
3690
num_nondust_htlcs,
3675
- htlcs_included,
3691
+ htlcs_included: htlcs_in_tx ,
3676
3692
local_balance_msat: value_to_self_msat,
3677
3693
remote_balance_msat: value_to_remote_msat,
3678
3694
inbound_htlc_preimages,
0 commit comments