Skip to content

Commit f736d90

Browse files
committed
f: Create IncludedHTLC type to enforce dust-vs-nondust sorting to TxBuilder
This is a temporary type that will be removed once we let `TxBuilder` choose which HTLCs are dust and which are non-dust.
1 parent 5ade2f3 commit f736d90

File tree

3 files changed

+55
-37
lines changed

3 files changed

+55
-37
lines changed

lightning/src/ln/chan_utils.rs

Lines changed: 0 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -647,23 +647,6 @@ impl HTLCOutputInCommitment {
647647
&& self.cltv_expiry == other.cltv_expiry
648648
&& self.payment_hash == other.payment_hash
649649
}
650-
651-
pub(crate) fn is_dust(
652-
&self, feerate_per_kw: u32, broadcaster_dust_limit_sat: u64, features: &ChannelTypeFeatures,
653-
) -> bool {
654-
let htlc_tx_fee_sat = if features.supports_anchors_zero_fee_htlc_tx() {
655-
0
656-
} else {
657-
let htlc_tx_weight = if self.offered {
658-
htlc_timeout_tx_weight(features)
659-
} else {
660-
htlc_success_tx_weight(features)
661-
};
662-
// As required by the spec, round down
663-
feerate_per_kw as u64 * htlc_tx_weight / 1000
664-
};
665-
self.amount_msat / 1000 < broadcaster_dust_limit_sat + htlc_tx_fee_sat
666-
}
667650
}
668651

669652
impl_writeable_tlv_based!(HTLCOutputInCommitment, {

lightning/src/ln/channel.rs

Lines changed: 37 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -450,6 +450,15 @@ impl OutboundHTLCOutput {
450450
}
451451
}
452452

453+
#[derive(Clone, Debug)]
454+
pub(crate) struct IncludedHTLC {
455+
pub offered: bool,
456+
pub amount_msat: u64,
457+
pub cltv_expiry: u32,
458+
pub payment_hash: PaymentHash,
459+
pub is_dust: bool,
460+
}
461+
453462
/// See AwaitingRemoteRevoke ChannelState for more info
454463
#[cfg_attr(test, derive(Clone, Debug, PartialEq))]
455464
enum HTLCUpdateAwaitingACK {
@@ -4566,7 +4575,8 @@ where
45664575
let feerate_per_kw = self.get_commitment_feerate(funding, generated_by_local);
45674576

45684577
let num_htlcs = self.pending_inbound_htlcs.len() + self.pending_outbound_htlcs.len();
4569-
let mut htlcs_included: Vec<(HTLCOutputInCommitment, Option<&HTLCSource>)> = Vec::with_capacity(num_htlcs);
4578+
let mut htlc_source_table: Vec<(HTLCOutputInCommitment, Option<&HTLCSource>)> = Vec::with_capacity(num_htlcs);
4579+
let mut htlcs_included: Vec<IncludedHTLC> = Vec::with_capacity(num_htlcs);
45704580
let mut value_to_self_claimed_msat = 0;
45714581
let mut value_to_remote_claimed_msat = 0;
45724582

@@ -4583,15 +4593,29 @@ where
45834593
amount_msat: $htlc.amount_msat,
45844594
cltv_expiry: $htlc.cltv_expiry,
45854595
payment_hash: $htlc.payment_hash,
4586-
transaction_output_index: None
4596+
transaction_output_index: None,
4597+
}
4598+
}
4599+
}
4600+
4601+
macro_rules! get_included_htlc {
4602+
($htlc: expr, $offered: expr, $is_dust: expr) => {
4603+
IncludedHTLC {
4604+
offered: $offered,
4605+
amount_msat: $htlc.amount_msat,
4606+
cltv_expiry: $htlc.cltv_expiry,
4607+
payment_hash: $htlc.payment_hash,
4608+
is_dust: $is_dust,
45874609
}
45884610
}
45894611
}
45904612

45914613
macro_rules! add_htlc_output {
4592-
($htlc: expr, $outbound: expr, $source: expr) => {
4593-
let htlc_in_tx = get_htlc_in_commitment!($htlc, $outbound == local);
4594-
htlcs_included.push((htlc_in_tx, $source));
4614+
($htlc: expr, $outbound: expr, $source: expr, $is_dust: expr) => {
4615+
let table_htlc = get_htlc_in_commitment!($htlc, $outbound == local);
4616+
let included_htlc = get_included_htlc!($htlc, $outbound == local, $is_dust);
4617+
htlc_source_table.push((table_htlc, $source));
4618+
htlcs_included.push(included_htlc);
45954619
}
45964620
}
45974621

@@ -4601,7 +4625,8 @@ where
46014625
for htlc in self.pending_inbound_htlcs.iter() {
46024626
if htlc.state.included_in_commitment(generated_by_local) {
46034627
log_trace!(logger, " ...including inbound {} HTLC {} (hash {}) with value {}", htlc.state, htlc.htlc_id, htlc.payment_hash, htlc.amount_msat);
4604-
add_htlc_output!(htlc, false, None);
4628+
let is_dust = htlc.is_dust(local, feerate_per_kw, broadcaster_dust_limit_sat, funding.get_channel_type());
4629+
add_htlc_output!(htlc, false, None, is_dust);
46054630
} else {
46064631
log_trace!(logger, " ...not including inbound HTLC {} (hash {}) with value {} due to state ({})", htlc.htlc_id, htlc.payment_hash, htlc.amount_msat, htlc.state);
46074632
if let Some(preimage) = htlc.state.preimage() {
@@ -4617,7 +4642,8 @@ where
46174642
}
46184643
if htlc.state.included_in_commitment(generated_by_local) {
46194644
log_trace!(logger, " ...including outbound {} HTLC {} (hash {}) with value {}", htlc.state, htlc.htlc_id, htlc.payment_hash, htlc.amount_msat);
4620-
add_htlc_output!(htlc, true, Some(&htlc.source));
4645+
let is_dust = htlc.is_dust(local, feerate_per_kw, broadcaster_dust_limit_sat, funding.get_channel_type());
4646+
add_htlc_output!(htlc, true, Some(&htlc.source), is_dust);
46214647
} else {
46224648
log_trace!(logger, " ...not including outbound HTLC {} (hash {}) with value {} due to state ({})", htlc.htlc_id, htlc.payment_hash, htlc.amount_msat, htlc.state);
46234649
if htlc.state.preimage().is_some() {
@@ -4639,7 +4665,7 @@ where
46394665
&funding.channel_transaction_parameters,
46404666
&self.secp_ctx,
46414667
value_to_self_msat,
4642-
htlcs_included.iter().map(|(htlc, _source)| htlc).cloned().collect(),
4668+
htlcs_included,
46434669
feerate_per_kw,
46444670
broadcaster_dust_limit_sat,
46454671
logger,
@@ -4652,7 +4678,7 @@ where
46524678
// This brute-force search is O(n^2) over ~1k HTLCs in the worst case. This case is very
46534679
// rare at the moment.
46544680
for nondust_htlc in tx.nondust_htlcs() {
4655-
let htlc = htlcs_included
4681+
let htlc = htlc_source_table
46564682
.iter_mut()
46574683
.filter(|(htlc, _source)| htlc.transaction_output_index.is_none())
46584684
.find_map(|(htlc, _source)| {
@@ -4668,7 +4694,7 @@ where
46684694

46694695
// This places the non-dust HTLC-source pairs first, in the order they appear in the
46704696
// commitment transaction, followed by the dust HTLC-source pairs.
4671-
htlcs_included.sort_unstable_by(|(htlc_a, _), (htlc_b, _)| {
4697+
htlc_source_table.sort_unstable_by(|(htlc_a, _), (htlc_b, _)| {
46724698
match (htlc_a.transaction_output_index, htlc_b.transaction_output_index) {
46734699
// `None` is smaller than `Some`, but we want `Some` ordered before `None` in the vector
46744700
(None, Some(_)) => cmp::Ordering::Greater,
@@ -4680,7 +4706,7 @@ where
46804706
CommitmentData {
46814707
tx,
46824708
stats,
4683-
htlcs_included,
4709+
htlcs_included: htlc_source_table,
46844710
inbound_htlc_preimages,
46854711
outbound_htlc_preimages,
46864712
}

lightning/src/sign/tx_builder.rs

Lines changed: 18 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ use bitcoin::secp256k1::{self, PublicKey, Secp256k1};
77
use crate::ln::chan_utils::{
88
commit_tx_fee_sat, ChannelTransactionParameters, CommitmentTransaction, HTLCOutputInCommitment,
99
};
10-
use crate::ln::channel::{CommitmentStats, ANCHOR_OUTPUT_VALUE_SATOSHI};
10+
use crate::ln::channel::{CommitmentStats, IncludedHTLC, ANCHOR_OUTPUT_VALUE_SATOSHI};
1111
use crate::prelude::*;
1212
use crate::types::features::ChannelTypeFeatures;
1313
use crate::util::logger::Logger;
@@ -21,7 +21,7 @@ pub(crate) trait TxBuilder {
2121
fn build_commitment_transaction<L: Deref>(
2222
&self, local: bool, commitment_number: u64, per_commitment_point: &PublicKey,
2323
channel_parameters: &ChannelTransactionParameters, secp_ctx: &Secp256k1<secp256k1::All>,
24-
value_to_self_msat: u64, htlcs_in_tx: Vec<HTLCOutputInCommitment>, feerate_per_kw: u32,
24+
value_to_self_msat: u64, htlcs_in_tx: Vec<IncludedHTLC>, feerate_per_kw: u32,
2525
broadcaster_dust_limit_satoshis: u64, logger: &L,
2626
) -> (CommitmentTransaction, CommitmentStats)
2727
where
@@ -72,7 +72,7 @@ impl TxBuilder for SpecTxBuilder {
7272
fn build_commitment_transaction<L: Deref>(
7373
&self, local: bool, commitment_number: u64, per_commitment_point: &PublicKey,
7474
channel_parameters: &ChannelTransactionParameters, secp_ctx: &Secp256k1<secp256k1::All>,
75-
value_to_self_msat: u64, mut htlcs_in_tx: Vec<HTLCOutputInCommitment>, feerate_per_kw: u32,
75+
value_to_self_msat: u64, mut htlcs_in_tx: Vec<IncludedHTLC>, feerate_per_kw: u32,
7676
broadcaster_dust_limit_satoshis: u64, logger: &L,
7777
) -> (CommitmentTransaction, CommitmentStats)
7878
where
@@ -89,11 +89,7 @@ impl TxBuilder for SpecTxBuilder {
8989
} else {
9090
remote_htlc_total_msat += htlc.amount_msat;
9191
}
92-
if htlc.is_dust(
93-
feerate_per_kw,
94-
broadcaster_dust_limit_satoshis,
95-
&channel_parameters.channel_type_features,
96-
) {
92+
if htlc.is_dust {
9793
log_trace!(
9894
logger,
9995
" ...trimming {} HTLC with value {}sat, hash {}, due to dust limit {}",
@@ -182,7 +178,20 @@ impl TxBuilder for SpecTxBuilder {
182178
to_broadcaster_value_sat,
183179
to_countersignatory_value_sat,
184180
feerate_per_kw,
185-
htlcs_in_tx,
181+
htlcs_in_tx
182+
.into_iter()
183+
.map(|htlc| {
184+
// We filtered out all dust HTLCs above
185+
debug_assert!(!htlc.is_dust);
186+
HTLCOutputInCommitment {
187+
offered: htlc.offered,
188+
amount_msat: htlc.amount_msat,
189+
cltv_expiry: htlc.cltv_expiry,
190+
payment_hash: htlc.payment_hash,
191+
transaction_output_index: None,
192+
}
193+
})
194+
.collect(),
186195
&directed_parameters,
187196
secp_ctx,
188197
);

0 commit comments

Comments
 (0)