@@ -3590,9 +3590,11 @@ impl<SP: Deref> ChannelContext<SP> where SP::Target: SignerProvider {
3590
3590
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
3591
3591
where L::Target: Logger
3592
3592
{
3593
- let mut included_dust_htlcs: Vec<(HTLCOutputInCommitment, Option<&HTLCSource>)> = Vec::new();
3594
3593
let num_htlcs = self.pending_inbound_htlcs.len() + self.pending_outbound_htlcs.len();
3595
- let mut included_non_dust_htlcs: Vec<(HTLCOutputInCommitment, Option<&HTLCSource>)> = Vec::with_capacity(num_htlcs);
3594
+
3595
+ // This will contain all the htlcs included on the commitment transaction due to their state, both dust, and non-dust.
3596
+ // Non-dust htlcs will come first, with their output indices populated, then dust htlcs, with their output indices set to `None`.
3597
+ let mut htlcs_in_tx: Vec<(HTLCOutputInCommitment, Option<&HTLCSource>)> = Vec::with_capacity(num_htlcs);
3596
3598
3597
3599
let broadcaster_dust_limit_satoshis = if local { self.holder_dust_limit_satoshis } else { self.counterparty_dust_limit_satoshis };
3598
3600
let mut remote_htlc_total_msat = 0;
@@ -3630,42 +3632,8 @@ impl<SP: Deref> ChannelContext<SP> where SP::Target: SignerProvider {
3630
3632
}
3631
3633
}
3632
3634
3633
- macro_rules! add_htlc_output {
3634
- ($htlc: expr, $outbound: expr, $source: expr, $state_name: expr) => {
3635
- if $outbound == local { // "offered HTLC output"
3636
- let htlc_in_tx = get_htlc_in_commitment!($htlc, true);
3637
- let htlc_tx_fee = if self.get_channel_type().supports_anchors_zero_fee_htlc_tx() {
3638
- 0
3639
- } else {
3640
- feerate_per_kw as u64 * htlc_timeout_tx_weight(self.get_channel_type()) / 1000
3641
- };
3642
- if $htlc.amount_msat / 1000 >= broadcaster_dust_limit_satoshis + htlc_tx_fee {
3643
- log_trace!(logger, " ...including {} {} HTLC {} (hash {}) with value {}", if $outbound { "outbound" } else { "inbound" }, $state_name, $htlc.htlc_id, &$htlc.payment_hash, $htlc.amount_msat);
3644
- included_non_dust_htlcs.push((htlc_in_tx, $source));
3645
- } else {
3646
- 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);
3647
- included_dust_htlcs.push((htlc_in_tx, $source));
3648
- }
3649
- } else {
3650
- let htlc_in_tx = get_htlc_in_commitment!($htlc, false);
3651
- let htlc_tx_fee = if self.get_channel_type().supports_anchors_zero_fee_htlc_tx() {
3652
- 0
3653
- } else {
3654
- feerate_per_kw as u64 * htlc_success_tx_weight(self.get_channel_type()) / 1000
3655
- };
3656
- if $htlc.amount_msat / 1000 >= broadcaster_dust_limit_satoshis + htlc_tx_fee {
3657
- log_trace!(logger, " ...including {} {} HTLC {} (hash {}) with value {}", if $outbound { "outbound" } else { "inbound" }, $state_name, $htlc.htlc_id, &$htlc.payment_hash, $htlc.amount_msat);
3658
- included_non_dust_htlcs.push((htlc_in_tx, $source));
3659
- } else {
3660
- 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);
3661
- included_dust_htlcs.push((htlc_in_tx, $source));
3662
- }
3663
- }
3664
- }
3665
- }
3666
-
3635
+ // Read the state of htlcs and determine their inclusion in the commitment transaction
3667
3636
let mut inbound_htlc_preimages: Vec<PaymentPreimage> = Vec::new();
3668
-
3669
3637
for ref htlc in self.pending_inbound_htlcs.iter() {
3670
3638
let (include, state_name) = match htlc.state {
3671
3639
InboundHTLCState::RemoteAnnounced(_) => (!generated_by_local, "RemoteAnnounced"),
@@ -3676,8 +3644,9 @@ impl<SP: Deref> ChannelContext<SP> where SP::Target: SignerProvider {
3676
3644
};
3677
3645
3678
3646
if include {
3679
- add_htlc_output!(htlc, false, None, state_name);
3680
- remote_htlc_total_msat += htlc.amount_msat;
3647
+ log_trace!(logger, " ...including inbound HTLC {} (hash {}) with value {} due to state ({})", htlc.htlc_id, &htlc.payment_hash, htlc.amount_msat, state_name);
3648
+ let htlc = get_htlc_in_commitment!(htlc, !local);
3649
+ htlcs_in_tx.push((htlc, None));
3681
3650
} else {
3682
3651
log_trace!(logger, " ...not including inbound HTLC {} (hash {}) with value {} due to state ({})", htlc.htlc_id, &htlc.payment_hash, htlc.amount_msat, state_name);
3683
3652
match &htlc.state {
@@ -3692,7 +3661,6 @@ impl<SP: Deref> ChannelContext<SP> where SP::Target: SignerProvider {
3692
3661
3693
3662
3694
3663
let mut outbound_htlc_preimages: Vec<PaymentPreimage> = Vec::new();
3695
-
3696
3664
for ref htlc in self.pending_outbound_htlcs.iter() {
3697
3665
let (include, state_name) = match htlc.state {
3698
3666
OutboundHTLCState::LocalAnnounced(_) => (generated_by_local, "LocalAnnounced"),
@@ -3714,8 +3682,9 @@ impl<SP: Deref> ChannelContext<SP> where SP::Target: SignerProvider {
3714
3682
}
3715
3683
3716
3684
if include {
3717
- add_htlc_output!(htlc, true, Some(&htlc.source), state_name);
3718
- local_htlc_total_msat += htlc.amount_msat;
3685
+ log_trace!(logger, " ...including outbound HTLC {} (hash {}) with value {} due to state ({})", htlc.htlc_id, &htlc.payment_hash, htlc.amount_msat, state_name);
3686
+ let htlc_in_tx = get_htlc_in_commitment!(htlc, local);
3687
+ htlcs_in_tx.push((htlc_in_tx, Some(&htlc.source)));
3719
3688
} else {
3720
3689
log_trace!(logger, " ...not including outbound HTLC {} (hash {}) with value {} due to state ({})", htlc.htlc_id, &htlc.payment_hash, htlc.amount_msat, state_name);
3721
3690
match htlc.state {
@@ -3729,6 +3698,46 @@ impl<SP: Deref> ChannelContext<SP> where SP::Target: SignerProvider {
3729
3698
}
3730
3699
}
3731
3700
3701
+ // Trim dust htlcs
3702
+ let mut included_non_dust_htlcs: Vec<_> = htlcs_in_tx.iter_mut().map(|(htlc, _)| htlc).collect();
3703
+ included_non_dust_htlcs.retain(|htlc| {
3704
+ let outbound = local == htlc.offered;
3705
+ if outbound {
3706
+ local_htlc_total_msat += htlc.amount_msat;
3707
+ } else {
3708
+ remote_htlc_total_msat += htlc.amount_msat;
3709
+ }
3710
+ let htlc_tx_fee = if self.get_channel_type().supports_anchors_zero_fee_htlc_tx() {
3711
+ 0
3712
+ } else {
3713
+ feerate_per_kw as u64
3714
+ * if htlc.offered {
3715
+ chan_utils::htlc_timeout_tx_weight(self.get_channel_type())
3716
+ } else {
3717
+ chan_utils::htlc_success_tx_weight(self.get_channel_type())
3718
+ } / 1000
3719
+ };
3720
+ if htlc.amount_msat / 1000 >= broadcaster_dust_limit_satoshis + htlc_tx_fee {
3721
+ log_trace!(
3722
+ logger,
3723
+ " ...creating output for {} non-dust HTLC (hash {}) with value {}",
3724
+ if outbound { "outbound" } else { "inbound" },
3725
+ htlc.payment_hash,
3726
+ htlc.amount_msat
3727
+ );
3728
+ true
3729
+ } else {
3730
+ log_trace!(
3731
+ logger,
3732
+ " ...trimming {} HTLC (hash {}) with value {} due to dust limit",
3733
+ if outbound { "outbound" } else { "inbound" },
3734
+ htlc.payment_hash,
3735
+ htlc.amount_msat
3736
+ );
3737
+ false
3738
+ }
3739
+ });
3740
+
3732
3741
// TODO: When MSRV >= 1.66.0, use u64::checked_add_signed
3733
3742
let mut value_to_self_msat = u64::try_from(funding.value_to_self_msat as i64 + value_to_self_msat_offset).unwrap();
3734
3743
// Note that in case they have several just-awaiting-last-RAA fulfills in-progress (ie
@@ -3739,21 +3748,6 @@ impl<SP: Deref> ChannelContext<SP> where SP::Target: SignerProvider {
3739
3748
value_to_self_msat = u64::checked_sub(value_to_self_msat, local_htlc_total_msat).unwrap();
3740
3749
value_to_remote_msat = u64::checked_sub(value_to_remote_msat, remote_htlc_total_msat).unwrap();
3741
3750
3742
- #[cfg(debug_assertions)]
3743
- {
3744
- // Make sure that the to_self/to_remote is always either past the appropriate
3745
- // channel_reserve *or* it is making progress towards it.
3746
- let mut broadcaster_max_commitment_tx_output = if generated_by_local {
3747
- funding.holder_max_commitment_tx_output.lock().unwrap()
3748
- } else {
3749
- funding.counterparty_max_commitment_tx_output.lock().unwrap()
3750
- };
3751
- debug_assert!(broadcaster_max_commitment_tx_output.0 <= value_to_self_msat || value_to_self_msat / 1000 >= funding.counterparty_selected_channel_reserve_satoshis.unwrap());
3752
- broadcaster_max_commitment_tx_output.0 = cmp::max(broadcaster_max_commitment_tx_output.0, value_to_self_msat);
3753
- debug_assert!(broadcaster_max_commitment_tx_output.1 <= value_to_remote_msat || value_to_remote_msat / 1000 >= funding.holder_selected_channel_reserve_satoshis);
3754
- broadcaster_max_commitment_tx_output.1 = cmp::max(broadcaster_max_commitment_tx_output.1, value_to_remote_msat);
3755
- }
3756
-
3757
3751
let total_fee_sat = commit_tx_fee_sat(feerate_per_kw, included_non_dust_htlcs.len(), &funding.channel_transaction_parameters.channel_type_features);
3758
3752
let anchors_val = if funding.channel_transaction_parameters.channel_type_features.supports_anchors_zero_fee_htlc_tx() { ANCHOR_OUTPUT_VALUE_SATOSHI * 2 } else { 0 };
3759
3753
let (value_to_self, value_to_remote) = if funding.is_outbound() {
@@ -3766,14 +3760,16 @@ impl<SP: Deref> ChannelContext<SP> where SP::Target: SignerProvider {
3766
3760
let mut value_to_b = if local { value_to_remote } else { value_to_self };
3767
3761
3768
3762
if value_to_a >= broadcaster_dust_limit_satoshis {
3769
- log_trace!(logger, " ...including {} output with value {}", if local { "to_local" } else { "to_remote" }, value_to_a);
3763
+ log_trace!(logger, " ...creating {} output with value {}", if local { "to_local" } else { "to_remote" }, value_to_a);
3770
3764
} else {
3765
+ log_trace!(logger, " ...trimming {} output with value {} due to dust limit", if local { "to_local" } else { "to_remote" }, value_to_a);
3771
3766
value_to_a = 0;
3772
3767
}
3773
3768
3774
3769
if value_to_b >= broadcaster_dust_limit_satoshis {
3775
- log_trace!(logger, " ...including {} output with value {}", if local { "to_remote" } else { "to_local" }, value_to_b);
3770
+ log_trace!(logger, " ...creating {} output with value {}", if local { "to_remote" } else { "to_local" }, value_to_b);
3776
3771
} else {
3772
+ log_trace!(logger, " ...trimming {} output with value {} due to dust limit", if local { "to_remote" } else { "to_local" }, value_to_b);
3777
3773
value_to_b = 0;
3778
3774
}
3779
3775
@@ -3787,21 +3783,41 @@ impl<SP: Deref> ChannelContext<SP> where SP::Target: SignerProvider {
3787
3783
value_to_a,
3788
3784
value_to_b,
3789
3785
feerate_per_kw,
3790
- included_non_dust_htlcs.iter_mut().map(|(htlc, _)| htlc).collect() ,
3786
+ included_non_dust_htlcs,
3791
3787
&channel_parameters,
3792
3788
&self.secp_ctx,
3793
3789
);
3794
- let mut htlcs_included = included_non_dust_htlcs;
3795
- // The unwrap is safe, because all non-dust HTLCs have been assigned an output index
3796
- htlcs_included.sort_unstable_by_key(|h| h.0.transaction_output_index.unwrap());
3797
- htlcs_included.append(&mut included_dust_htlcs);
3790
+
3791
+ #[cfg(debug_assertions)]
3792
+ {
3793
+ // Make sure that the to_self/to_remote is always either past the appropriate
3794
+ // channel_reserve *or* it is making progress towards it.
3795
+ let mut broadcaster_max_commitment_tx_output = if generated_by_local {
3796
+ funding.holder_max_commitment_tx_output.lock().unwrap()
3797
+ } else {
3798
+ funding.counterparty_max_commitment_tx_output.lock().unwrap()
3799
+ };
3800
+ debug_assert!(broadcaster_max_commitment_tx_output.0 <= value_to_self_msat || value_to_self_msat / 1000 >= funding.counterparty_selected_channel_reserve_satoshis.unwrap());
3801
+ broadcaster_max_commitment_tx_output.0 = cmp::max(broadcaster_max_commitment_tx_output.0, value_to_self_msat);
3802
+ debug_assert!(broadcaster_max_commitment_tx_output.1 <= value_to_remote_msat || value_to_remote_msat / 1000 >= funding.holder_selected_channel_reserve_satoshis);
3803
+ broadcaster_max_commitment_tx_output.1 = cmp::max(broadcaster_max_commitment_tx_output.1, value_to_remote_msat);
3804
+ }
3805
+
3806
+ htlcs_in_tx.sort_unstable_by(|(htlc_a, _), (htlc_b, _)| {
3807
+ match (htlc_a.transaction_output_index, htlc_b.transaction_output_index) {
3808
+ // `None` is smaller than `Some`, but we want `Some` ordered before `None` in the vector
3809
+ (None, Some(_)) => cmp::Ordering::Greater,
3810
+ (Some(_), None) => cmp::Ordering::Less,
3811
+ (l, r) => cmp::Ord::cmp(&l, &r),
3812
+ }
3813
+ });
3798
3814
3799
3815
CommitmentStats {
3800
3816
tx,
3801
3817
feerate_per_kw,
3802
3818
total_fee_sat,
3803
3819
num_nondust_htlcs,
3804
- htlcs_included,
3820
+ htlcs_included: htlcs_in_tx ,
3805
3821
local_balance_msat: value_to_self_msat,
3806
3822
remote_balance_msat: value_to_remote_msat,
3807
3823
inbound_htlc_preimages,
0 commit comments