Skip to content

Commit 84149fd

Browse files
Don't include below-dust inbound HTLCs in commit tx fee calculation
Also remove part of the holding cell channel reserve test that's newly failing but a bit of a redundant test anyway.
1 parent 773c2d1 commit 84149fd

File tree

2 files changed

+79
-44
lines changed

2 files changed

+79
-44
lines changed

lightning/src/ln/channel.rs

Lines changed: 48 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1729,10 +1729,23 @@ impl<ChanSigner: ChannelKeys> Channel<ChanSigner> {
17291729
// commitment tx. `addl_htcs` is an optional parameter allowing the caller
17301730
// to add a number of additional HTLCs to the calculation. Note that dust
17311731
// HTLCs are excluded.
1732-
fn next_local_commit_tx_fee_msat(&self, addl_htlcs: usize) -> u64 {
1732+
fn next_local_commit_tx_fee_msat(&self, new_htlc_amount: u64, fee_spike_buffer_htlc: Option<()>) -> u64 {
17331733
assert!(self.channel_outbound);
17341734

1735-
let mut their_acked_htlcs = self.pending_inbound_htlcs.len();
1735+
let mut addl_htlcs = 1;
1736+
if fee_spike_buffer_htlc.is_some() { addl_htlcs += 1; }
1737+
if new_htlc_amount / 1000 <= self.counterparty_dust_limit_satoshis {
1738+
addl_htlcs -= 1;
1739+
}
1740+
1741+
let mut their_acked_htlcs = 0;
1742+
for ref htlc in self.pending_inbound_htlcs.iter() {
1743+
if htlc.amount_msat / 1000 <= self.counterparty_dust_limit_satoshis {
1744+
continue
1745+
}
1746+
their_acked_htlcs += 1;
1747+
}
1748+
17361749
for ref htlc in self.pending_outbound_htlcs.iter() {
17371750
if htlc.amount_msat / 1000 <= self.holder_dust_limit_satoshis {
17381751
continue
@@ -1760,13 +1773,27 @@ impl<ChanSigner: ChannelKeys> Channel<ChanSigner> {
17601773
// next commitment tx. `addl_htcs` is an optional parameter allowing the caller
17611774
// to add a number of additional HTLCs to the calculation. Note that dust HTLCs
17621775
// are excluded.
1763-
fn next_remote_commit_tx_fee_msat(&self, addl_htlcs: usize) -> u64 {
1776+
fn next_remote_commit_tx_fee_msat(&self, new_htlc_amount: u64, fee_spike_buffer_htlc: Option<()>) -> u64 {
17641777
assert!(!self.channel_outbound);
17651778

1766-
// When calculating the set of HTLCs which will be included in their next
1767-
// commitment_signed, all inbound HTLCs are included (as all states imply it will be
1768-
// included) and only committed outbound HTLCs, see below.
1769-
let mut their_acked_htlcs = self.pending_inbound_htlcs.len();
1779+
let mut addl_htlcs = 1;
1780+
if fee_spike_buffer_htlc.is_some() { addl_htlcs += 1; }
1781+
if new_htlc_amount / 1000 <= self.holder_dust_limit_satoshis {
1782+
addl_htlcs -= 1;
1783+
}
1784+
1785+
// When calculating the set of HTLCs which will be included in their next commitment_signed, all
1786+
// non-dust inbound HTLCs are included (as all states imply it will be included) and only
1787+
// committed outbound HTLCs, see below.
1788+
// let mut their_acked_htlcs = self.pending_inbound_htlcs.len();
1789+
let mut their_acked_htlcs = 0;
1790+
for ref htlc in self.pending_inbound_htlcs.iter() {
1791+
if htlc.amount_msat / 1000 <= self.holder_dust_limit_satoshis {
1792+
continue
1793+
}
1794+
their_acked_htlcs += 1;
1795+
}
1796+
17701797
for ref htlc in self.pending_outbound_htlcs.iter() {
17711798
if htlc.amount_msat / 1000 <= self.counterparty_dust_limit_satoshis {
17721799
continue
@@ -1848,8 +1875,7 @@ impl<ChanSigner: ChannelKeys> Channel<ChanSigner> {
18481875
// Check that the remote can afford to pay for this HTLC on-chain at the current
18491876
// feerate_per_kw, while maintaining their channel reserve (as required by the spec).
18501877
let remote_commit_tx_fee_msat = if self.channel_outbound { 0 } else {
1851-
// +1 for this HTLC.
1852-
self.next_remote_commit_tx_fee_msat(1)
1878+
self.next_remote_commit_tx_fee_msat(msg.amount_msat, None) // Don't include the extra fee spike buffer HTLC in calculations
18531879
};
18541880
if pending_remote_value_msat - msg.amount_msat < remote_commit_tx_fee_msat {
18551881
return Err(ChannelError::Close("Remote HTLC add would not leave enough to pay for fees".to_owned()));
@@ -1862,14 +1888,15 @@ impl<ChanSigner: ChannelKeys> Channel<ChanSigner> {
18621888
}
18631889

18641890
if !self.channel_outbound {
1865-
// `+1` for this HTLC, `2 *` and `+1` fee spike buffer we keep for the remote. This deviates from the
1866-
// spec because in the spec, the fee spike buffer requirement doesn't exist on the receiver's side,
1867-
// only on the sender's.
1868-
// Note that when we eventually remove support for fee updates and switch to anchor output fees,
1869-
// we will drop the `2 *`, since we no longer be as sensitive to fee spikes. But, keep the extra +1
1870-
// as we should still be able to afford adding this HTLC plus one more future HTLC, regardless of
1871-
// being sensitive to fee spikes.
1872-
let remote_fee_cost_incl_stuck_buffer_msat = 2 * self.next_remote_commit_tx_fee_msat(1 + 1);
1891+
// `2 *` and `Some(())` is for the fee spike buffer we keep for the remote. This deviates from
1892+
// the spec because in the spec, the fee spike buffer requirement doesn't exist on the
1893+
// receiver's side, only on the sender's.
1894+
// Note that when we eventually remove support for fee updates and switch to anchor output
1895+
// fees, we will drop the `2 *`, since we no longer be as sensitive to fee spikes. But, keep
1896+
// the extra htlc when calculating the next remote commitment transaction fee as we should
1897+
// still be able to afford adding this HTLC plus one more future HTLC, regardless of being
1898+
// sensitive to fee spikes.
1899+
let remote_fee_cost_incl_stuck_buffer_msat = 2 * self.next_remote_commit_tx_fee_msat(msg.amount_msat, Some(()));
18731900
if pending_remote_value_msat - msg.amount_msat - chan_reserve_msat < remote_fee_cost_incl_stuck_buffer_msat {
18741901
// Note that if the pending_forward_status is not updated here, then it's because we're already failing
18751902
// the HTLC, i.e. its status is already set to failing.
@@ -1878,9 +1905,7 @@ impl<ChanSigner: ChannelKeys> Channel<ChanSigner> {
18781905
}
18791906
} else {
18801907
// Check that they won't violate our local required channel reserve by adding this HTLC.
1881-
1882-
// +1 for this HTLC.
1883-
let local_commit_tx_fee_msat = self.next_local_commit_tx_fee_msat(1);
1908+
let local_commit_tx_fee_msat = self.next_local_commit_tx_fee_msat(msg.amount_msat, None);
18841909
if self.value_to_self_msat < self.counterparty_selected_channel_reserve_satoshis * 1000 + local_commit_tx_fee_msat {
18851910
return Err(ChannelError::Close("Cannot accept HTLC that would put our balance under counterparty-announced channel reserve value".to_owned()));
18861911
}
@@ -3738,11 +3763,9 @@ impl<ChanSigner: ChannelKeys> Channel<ChanSigner> {
37383763

37393764
if !self.channel_outbound {
37403765
// Check that we won't violate the remote channel reserve by adding this HTLC.
3741-
37423766
let counterparty_balance_msat = self.channel_value_satoshis * 1000 - self.value_to_self_msat;
37433767
let holder_selected_chan_reserve_msat = Channel::<ChanSigner>::get_holder_selected_channel_reserve_satoshis(self.channel_value_satoshis);
3744-
// 1 additional HTLC corresponding to this HTLC.
3745-
let counterparty_commit_tx_fee_msat = self.next_remote_commit_tx_fee_msat(1);
3768+
let counterparty_commit_tx_fee_msat = self.next_remote_commit_tx_fee_msat(amount_msat, None);
37463769
if counterparty_balance_msat < holder_selected_chan_reserve_msat + counterparty_commit_tx_fee_msat {
37473770
return Err(ChannelError::Ignore("Cannot send value that would put counterparty balance under holder-announced channel reserve value".to_owned()));
37483771
}
@@ -3753,10 +3776,9 @@ impl<ChanSigner: ChannelKeys> Channel<ChanSigner> {
37533776
return Err(ChannelError::Ignore(format!("Cannot send value that would overdraw remaining funds. Amount: {}, pending value to self {}", amount_msat, pending_value_to_self_msat)));
37543777
}
37553778

3756-
// The `+1` is for the HTLC currently being added to the commitment tx and
3757-
// the `2 *` and `+1` are for the fee spike buffer.
3779+
// `2 *` and extra HTLC are for the fee spike buffer.
37583780
let commit_tx_fee_msat = if self.channel_outbound {
3759-
2 * self.next_local_commit_tx_fee_msat(1 + 1)
3781+
2 * self.next_local_commit_tx_fee_msat(amount_msat, Some(()))
37603782
} else { 0 };
37613783
if pending_value_to_self_msat - amount_msat < commit_tx_fee_msat {
37623784
return Err(ChannelError::Ignore(format!("Cannot send value that would not leave enough to pay for fees. Pending value to self: {}. local_commit_tx_fee {}", pending_value_to_self_msat, commit_tx_fee_msat)));

lightning/src/ln/functional_tests.rs

Lines changed: 31 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1764,7 +1764,7 @@ fn test_chan_reserve_violation_outbound_htlc_inbound_chan() {
17641764
}}
17651765
};
17661766

1767-
let (route, our_payment_hash, _) = get_route_and_payment_hash!(1000);
1767+
let (route, our_payment_hash, _) = get_route_and_payment_hash!(1001000);
17681768
unwrap_send_err!(nodes[1].node.send_payment(&route, our_payment_hash, &None), true, APIError::ChannelUnavailable { ref err },
17691769
assert_eq!(err, "Cannot send value that would put counterparty balance under holder-announced channel reserve value"));
17701770
assert!(nodes[1].node.get_and_clear_pending_msg_events().is_empty());
@@ -1822,6 +1822,36 @@ fn test_chan_reserve_violation_inbound_htlc_outbound_channel() {
18221822
check_added_monitors!(nodes[0], 1);
18231823
}
18241824

1825+
#[test]
1826+
fn test_chan_reserve_dust_htlcs() {
1827+
// Test that if we receive many dust HTLCs over an inbound channel, they don't count when
1828+
// calculating our counterparty's commitment transaction fee (this was previously broken).
1829+
let chanmon_cfgs = create_chanmon_cfgs(2);
1830+
let node_cfgs = create_node_cfgs(2, &chanmon_cfgs);
1831+
let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None, None]);
1832+
let mut nodes = create_network(2, &node_cfgs, &node_chanmgrs);
1833+
create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 100000, 98000000, InitFeatures::known(), InitFeatures::known());
1834+
1835+
let payment_amt = 46000; // Dust amount
1836+
// In the previous code, these first four payments would succeed.
1837+
let (_, _) = route_payment(&nodes[0], &[&nodes[1]], payment_amt);
1838+
let (_, _) = route_payment(&nodes[0], &[&nodes[1]], payment_amt);
1839+
let (_, _) = route_payment(&nodes[0], &[&nodes[1]], payment_amt);
1840+
let (_, _) = route_payment(&nodes[0], &[&nodes[1]], payment_amt);
1841+
1842+
// Then these next 5 would be interpreted by nodes[1] as violating the fee spike buffer.
1843+
let (_, _) = route_payment(&nodes[0], &[&nodes[1]], payment_amt);
1844+
let (_, _) = route_payment(&nodes[0], &[&nodes[1]], payment_amt);
1845+
let (_, _) = route_payment(&nodes[0], &[&nodes[1]], payment_amt);
1846+
let (_, _) = route_payment(&nodes[0], &[&nodes[1]], payment_amt);
1847+
let (_, _) = route_payment(&nodes[0], &[&nodes[1]], payment_amt);
1848+
1849+
// And this last payment previously resulted in nodes[1] closing on its inbound-channel
1850+
// counterparty, because it counted all the previous dust HTLCs against nodes[0]'s commitment
1851+
// transaction fee and therefore perceived this next payment as a channel reserve violation.
1852+
let (_, _) = route_payment(&nodes[0], &[&nodes[1]], payment_amt);
1853+
}
1854+
18251855
#[test]
18261856
fn test_chan_reserve_violation_inbound_htlc_inbound_chan() {
18271857
let chanmon_cfgs = create_chanmon_cfgs(3);
@@ -2133,23 +2163,6 @@ fn test_channel_reserve_holding_cell_htlcs() {
21332163

21342164
let commit_tx_fee_0_htlcs = 2*commit_tx_fee_msat(feerate, 1);
21352165
let recv_value_3 = commit_tx_fee_2_htlcs - commit_tx_fee_0_htlcs - total_fee_msat;
2136-
{
2137-
let (route, our_payment_hash, _) = get_route_and_payment_hash!(recv_value_3 + 1);
2138-
let err = nodes[0].node.send_payment(&route, our_payment_hash, &None).err().unwrap();
2139-
match err {
2140-
PaymentSendFailure::AllFailedRetrySafe(ref fails) => {
2141-
match &fails[0] {
2142-
&APIError::ChannelUnavailable{ref err} =>
2143-
assert!(regex::Regex::new(r"Cannot send value that would put our balance under counterparty-announced channel reserve value \(\d+\)").unwrap().is_match(err)),
2144-
_ => panic!("Unexpected error variant"),
2145-
}
2146-
},
2147-
_ => panic!("Unexpected error variant"),
2148-
}
2149-
assert!(nodes[0].node.get_and_clear_pending_msg_events().is_empty());
2150-
nodes[0].logger.assert_log_contains("lightning::ln::channelmanager".to_string(), "Cannot send value that would put our balance under counterparty-announced channel reserve value".to_string(), 3);
2151-
}
2152-
21532166
send_payment(&nodes[0], &vec![&nodes[1], &nodes[2]][..], recv_value_3, recv_value_3);
21542167

21552168
let commit_tx_fee_1_htlc = 2*commit_tx_fee_msat(feerate, 1 + 1);

0 commit comments

Comments
 (0)