Skip to content

Commit 09030d4

Browse files
committed
Assert dust exposure exhaustion in the excess fees are dust test
The payments in this test previously failed for reasons other than exhausting the dust exposure limit with excess fees. Upon payment failures, we now check the logs to assert failures due to dust exposure exhaustion.
1 parent 2c89d30 commit 09030d4

File tree

1 file changed

+80
-12
lines changed

1 file changed

+80
-12
lines changed

lightning/src/ln/functional_tests.rs

Lines changed: 80 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -10518,28 +10518,37 @@ fn test_max_dust_htlc_exposure() {
1051810518
}
1051910519

1052010520
#[test]
10521-
fn test_nondust_htlc_fees_are_dust() {
10522-
// Test that the transaction fees paid in nondust HTLCs count towards our dust limit
10521+
fn test_nondust_htlc_excess_fees_are_dust() {
10522+
// Test that the excess transaction fees paid in nondust HTLCs count towards our dust limit
10523+
const DEFAULT_FEERATE: u32 = 253;
10524+
const HIGH_FEERATE: u32 = 275;
10525+
const EXCESS_FEERATE: u32 = HIGH_FEERATE - DEFAULT_FEERATE;
1052310526
let chanmon_cfgs = create_chanmon_cfgs(3);
10527+
{
10528+
// Set the feerate of the channel funder above the `dust_exposure_limiting_feerate` of
10529+
// the fundee. This delta means that the fundee will add the mining fees of the commitment and
10530+
// htlc transactions in excess of its `dust_exposure_limiting_feerate` to its total dust htlc
10531+
// exposure.
10532+
let mut feerate_lock = chanmon_cfgs[1].fee_estimator.sat_per_kw.lock().unwrap();
10533+
*feerate_lock = HIGH_FEERATE;
10534+
}
1052410535
let node_cfgs = create_node_cfgs(3, &chanmon_cfgs);
1052510536

1052610537
let mut config = test_default_channel_config();
1052710538
// Set the dust limit to the default value
1052810539
config.channel_config.max_dust_htlc_exposure =
1052910540
MaxDustHTLCExposure::FeeRateMultiplier(10_000);
1053010541
// Make sure the HTLC limits don't get in the way
10531-
config.channel_handshake_limits.min_max_accepted_htlcs = 400;
10532-
config.channel_handshake_config.our_max_accepted_htlcs = 400;
10542+
config.channel_handshake_limits.min_max_accepted_htlcs = chan_utils::MAX_HTLCS;
10543+
config.channel_handshake_config.our_max_accepted_htlcs = chan_utils::MAX_HTLCS;
1053310544
config.channel_handshake_config.our_htlc_minimum_msat = 1;
10545+
config.channel_handshake_config.max_inbound_htlc_value_in_flight_percent_of_channel = 100;
1053410546

1053510547
let node_chanmgrs = create_node_chanmgrs(3, &node_cfgs, &[Some(config), Some(config), Some(config)]);
1053610548
let nodes = create_network(3, &node_cfgs, &node_chanmgrs);
1053710549

10538-
// Create a channel from 1 -> 0 but immediately push all of the funds towards 0
10539-
let chan_id_1 = create_announced_chan_between_nodes(&nodes, 1, 0).2;
10540-
while nodes[1].node.list_channels()[0].next_outbound_htlc_limit_msat > 0 {
10541-
send_payment(&nodes[1], &[&nodes[0]], nodes[1].node.list_channels()[0].next_outbound_htlc_limit_msat);
10542-
}
10550+
// Leave enough on the funder side to let it pay the mining fees for a commit tx with tons of htlcs
10551+
let chan_id_1 = create_announced_chan_between_nodes_with_value(&nodes, 1, 0, 1_000_000, 750_000_000).2;
1054310552

1054410553
// First get the channel one HTLC_VALUE HTLC away from the dust limit by sending dust HTLCs
1054510554
// repeatedly until we run out of space.
@@ -10559,16 +10568,24 @@ fn test_nondust_htlc_fees_are_dust() {
1055910568
assert_ne!(nodes[0].node.list_channels()[0].next_outbound_htlc_minimum_msat, 0,
1056010569
"Make sure we are able to send once we clear one HTLC");
1056110570

10571+
// Skip the router complaint when node 0 will attempt to pay node 1
10572+
let (route_0_1, payment_hash_0_1, _, payment_secret_0_1) = get_route_and_payment_hash!(nodes[0], nodes[1], dust_limit * 2);
10573+
10574+
assert_eq!(nodes[0].node.list_channels().len(), 1);
10575+
assert_eq!(nodes[1].node.list_channels().len(), 1);
10576+
assert_eq!(nodes[0].node.list_channels()[0].pending_inbound_htlcs.len(), 0);
10577+
assert_eq!(nodes[1].node.list_channels()[0].pending_outbound_htlcs.len(), 0);
10578+
1056210579
// At this point we have somewhere between dust_limit and dust_limit * 2 left in our dust
1056310580
// exposure limit, and we want to max that out using non-dust HTLCs.
1056410581
let commitment_tx_per_htlc_cost =
10565-
htlc_success_tx_weight(&ChannelTypeFeatures::empty()) * 253;
10582+
htlc_success_tx_weight(&ChannelTypeFeatures::empty()) * EXCESS_FEERATE as u64;
1056610583
let max_htlcs_remaining = dust_limit * 2 / commitment_tx_per_htlc_cost;
10567-
assert!(max_htlcs_remaining < 30,
10584+
assert!(max_htlcs_remaining < chan_utils::MAX_HTLCS.into(),
1056810585
"We should be able to fill our dust limit without too many HTLCs");
1056910586
for i in 0..max_htlcs_remaining + 1 {
1057010587
assert_ne!(i, max_htlcs_remaining);
10571-
if nodes[0].node.list_channels()[0].next_outbound_htlc_limit_msat < dust_limit {
10588+
if nodes[0].node.list_channels()[0].next_outbound_htlc_limit_msat <= dust_limit {
1057210589
// We found our limit, and it was less than max_htlcs_remaining!
1057310590
// At this point we can only send dust HTLCs as any non-dust HTLCs will overuse our
1057410591
// remaining dust exposure.
@@ -10577,6 +10594,57 @@ fn test_nondust_htlc_fees_are_dust() {
1057710594
route_payment(&nodes[0], &[&nodes[1]], dust_limit * 2);
1057810595
}
1057910596

10597+
assert_eq!(nodes[0].node.list_channels().len(), 1);
10598+
assert_eq!(nodes[1].node.list_channels().len(), 1);
10599+
assert_eq!(nodes[0].node.list_channels()[0].pending_inbound_htlcs.len(), 0);
10600+
assert_eq!(nodes[1].node.list_channels()[0].pending_outbound_htlcs.len(), 0);
10601+
10602+
// Send an additional non-dust htlc from 1 to 0, and check the complaint
10603+
let (route, payment_hash, _, payment_secret) = get_route_and_payment_hash!(nodes[1], nodes[0], dust_limit * 2);
10604+
nodes[1].node.send_payment_with_route(route, payment_hash,
10605+
RecipientOnionFields::secret_only(payment_secret), PaymentId(payment_hash.0)).unwrap();
10606+
check_added_monitors!(nodes[1], 1);
10607+
let mut events = nodes[1].node.get_and_clear_pending_msg_events();
10608+
assert_eq!(events.len(), 1);
10609+
let payment_event = SendEvent::from_event(events.remove(0));
10610+
nodes[0].node.handle_update_add_htlc(nodes[1].node.get_our_node_id(), &payment_event.msgs[0]);
10611+
commitment_signed_dance!(nodes[0], nodes[1], payment_event.commitment_msg, false);
10612+
expect_pending_htlcs_forwardable!(nodes[0]);
10613+
expect_htlc_handling_failed_destinations!(nodes[0].node.get_and_clear_pending_events(), &[HTLCDestination::FailedPayment { payment_hash }]);
10614+
nodes[0].logger.assert_log("lightning::ln::channel",
10615+
format!("Cannot accept value that would put our total dust exposure at {} over the limit {} on counterparty commitment tx",
10616+
2535000, 2530000), 1);
10617+
check_added_monitors!(nodes[0], 1);
10618+
10619+
// Clear the failed htlc
10620+
let updates = get_htlc_update_msgs!(nodes[0], nodes[1].node.get_our_node_id());
10621+
assert!(updates.update_add_htlcs.is_empty());
10622+
assert!(updates.update_fulfill_htlcs.is_empty());
10623+
assert_eq!(updates.update_fail_htlcs.len(), 1);
10624+
assert!(updates.update_fail_malformed_htlcs.is_empty());
10625+
assert!(updates.update_fee.is_none());
10626+
nodes[1].node.handle_update_fail_htlc(nodes[0].node.get_our_node_id(), &updates.update_fail_htlcs[0]);
10627+
commitment_signed_dance!(nodes[1], nodes[0], updates.commitment_signed, false);
10628+
expect_payment_failed!(nodes[1], payment_hash, false);
10629+
10630+
assert_eq!(nodes[0].node.list_channels().len(), 1);
10631+
assert_eq!(nodes[1].node.list_channels().len(), 1);
10632+
assert_eq!(nodes[0].node.list_channels()[0].pending_inbound_htlcs.len(), 0);
10633+
assert_eq!(nodes[1].node.list_channels()[0].pending_outbound_htlcs.len(), 0);
10634+
10635+
// Send an additional non-dust htlc from 0 to 1 using the pre-calculated route above, and check the immediate complaint
10636+
unwrap_send_err!(nodes[0], nodes[0].node.send_payment_with_route(route_0_1, payment_hash_0_1,
10637+
RecipientOnionFields::secret_only(payment_secret_0_1), PaymentId(payment_hash_0_1.0)
10638+
), true, APIError::ChannelUnavailable { .. }, {});
10639+
nodes[0].logger.assert_log("lightning::ln::outbound_payment",
10640+
format!("Failed to send along path due to error: Channel unavailable: Cannot send more than our next-HTLC maximum - {} msat", 2325000), 1);
10641+
assert!(nodes[0].node.get_and_clear_pending_msg_events().is_empty());
10642+
10643+
assert_eq!(nodes[0].node.list_channels().len(), 1);
10644+
assert_eq!(nodes[1].node.list_channels().len(), 1);
10645+
assert_eq!(nodes[0].node.list_channels()[0].pending_inbound_htlcs.len(), 0);
10646+
assert_eq!(nodes[1].node.list_channels()[0].pending_outbound_htlcs.len(), 0);
10647+
1058010648
// At this point non-dust HTLCs are no longer accepted from node 0 -> 1, we also check that
1058110649
// such HTLCs can't be routed over the same channel either.
1058210650
create_announced_chan_between_nodes(&nodes, 2, 0);

0 commit comments

Comments
 (0)