Skip to content

Commit 8ed5a23

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 177e51d commit 8ed5a23

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
@@ -10596,28 +10596,37 @@ fn test_max_dust_htlc_exposure() {
1059610596
}
1059710597

1059810598
#[test]
10599-
fn test_nondust_htlc_fees_are_dust() {
10600-
// Test that the transaction fees paid in nondust HTLCs count towards our dust limit
10599+
fn test_nondust_htlc_excess_fees_are_dust() {
10600+
// Test that the excess transaction fees paid in nondust HTLCs count towards our dust limit
10601+
const DEFAULT_FEERATE: u32 = 253;
10602+
const HIGH_FEERATE: u32 = 275;
10603+
const EXCESS_FEERATE: u32 = HIGH_FEERATE - DEFAULT_FEERATE;
1060110604
let chanmon_cfgs = create_chanmon_cfgs(3);
10605+
{
10606+
// Set the feerate of the channel funder above the `dust_exposure_limiting_feerate` of
10607+
// the fundee. This delta means that the fundee will add the mining fees of the commitment and
10608+
// htlc transactions in excess of its `dust_exposure_limiting_feerate` to its total dust htlc
10609+
// exposure.
10610+
let mut feerate_lock = chanmon_cfgs[1].fee_estimator.sat_per_kw.lock().unwrap();
10611+
*feerate_lock = HIGH_FEERATE;
10612+
}
1060210613
let node_cfgs = create_node_cfgs(3, &chanmon_cfgs);
1060310614

1060410615
let mut config = test_default_channel_config();
1060510616
// Set the dust limit to the default value
1060610617
config.channel_config.max_dust_htlc_exposure =
1060710618
MaxDustHTLCExposure::FeeRateMultiplier(10_000);
1060810619
// Make sure the HTLC limits don't get in the way
10609-
config.channel_handshake_limits.min_max_accepted_htlcs = 400;
10610-
config.channel_handshake_config.our_max_accepted_htlcs = 400;
10620+
config.channel_handshake_limits.min_max_accepted_htlcs = chan_utils::MAX_HTLCS;
10621+
config.channel_handshake_config.our_max_accepted_htlcs = chan_utils::MAX_HTLCS;
1061110622
config.channel_handshake_config.our_htlc_minimum_msat = 1;
10623+
config.channel_handshake_config.max_inbound_htlc_value_in_flight_percent_of_channel = 100;
1061210624

1061310625
let node_chanmgrs = create_node_chanmgrs(3, &node_cfgs, &[Some(config), Some(config), Some(config)]);
1061410626
let nodes = create_network(3, &node_cfgs, &node_chanmgrs);
1061510627

10616-
// Create a channel from 1 -> 0 but immediately push all of the funds towards 0
10617-
let chan_id_1 = create_announced_chan_between_nodes(&nodes, 1, 0).2;
10618-
while nodes[1].node.list_channels()[0].next_outbound_htlc_limit_msat > 0 {
10619-
send_payment(&nodes[1], &[&nodes[0]], nodes[1].node.list_channels()[0].next_outbound_htlc_limit_msat);
10620-
}
10628+
// Leave enough on the funder side to let it pay the mining fees for a commit tx with tons of htlcs
10629+
let chan_id_1 = create_announced_chan_between_nodes_with_value(&nodes, 1, 0, 1_000_000, 750_000_000).2;
1062110630

1062210631
// First get the channel one HTLC_VALUE HTLC away from the dust limit by sending dust HTLCs
1062310632
// repeatedly until we run out of space.
@@ -10637,16 +10646,24 @@ fn test_nondust_htlc_fees_are_dust() {
1063710646
assert_ne!(nodes[0].node.list_channels()[0].next_outbound_htlc_minimum_msat, 0,
1063810647
"Make sure we are able to send once we clear one HTLC");
1063910648

10649+
// Skip the router complaint when node 0 will attempt to pay node 1
10650+
let (route_0_1, payment_hash_0_1, _, payment_secret_0_1) = get_route_and_payment_hash!(nodes[0], nodes[1], dust_limit * 2);
10651+
10652+
assert_eq!(nodes[0].node.list_channels().len(), 1);
10653+
assert_eq!(nodes[1].node.list_channels().len(), 1);
10654+
assert_eq!(nodes[0].node.list_channels()[0].pending_inbound_htlcs.len(), 0);
10655+
assert_eq!(nodes[1].node.list_channels()[0].pending_outbound_htlcs.len(), 0);
10656+
1064010657
// At this point we have somewhere between dust_limit and dust_limit * 2 left in our dust
1064110658
// exposure limit, and we want to max that out using non-dust HTLCs.
1064210659
let commitment_tx_per_htlc_cost =
10643-
htlc_success_tx_weight(&ChannelTypeFeatures::empty()) * 253;
10660+
htlc_success_tx_weight(&ChannelTypeFeatures::empty()) * EXCESS_FEERATE as u64;
1064410661
let max_htlcs_remaining = dust_limit * 2 / commitment_tx_per_htlc_cost;
10645-
assert!(max_htlcs_remaining < 30,
10662+
assert!(max_htlcs_remaining < chan_utils::MAX_HTLCS.into(),
1064610663
"We should be able to fill our dust limit without too many HTLCs");
1064710664
for i in 0..max_htlcs_remaining + 1 {
1064810665
assert_ne!(i, max_htlcs_remaining);
10649-
if nodes[0].node.list_channels()[0].next_outbound_htlc_limit_msat < dust_limit {
10666+
if nodes[0].node.list_channels()[0].next_outbound_htlc_limit_msat <= dust_limit {
1065010667
// We found our limit, and it was less than max_htlcs_remaining!
1065110668
// At this point we can only send dust HTLCs as any non-dust HTLCs will overuse our
1065210669
// remaining dust exposure.
@@ -10655,6 +10672,57 @@ fn test_nondust_htlc_fees_are_dust() {
1065510672
route_payment(&nodes[0], &[&nodes[1]], dust_limit * 2);
1065610673
}
1065710674

10675+
assert_eq!(nodes[0].node.list_channels().len(), 1);
10676+
assert_eq!(nodes[1].node.list_channels().len(), 1);
10677+
assert_eq!(nodes[0].node.list_channels()[0].pending_inbound_htlcs.len(), 0);
10678+
assert_eq!(nodes[1].node.list_channels()[0].pending_outbound_htlcs.len(), 0);
10679+
10680+
// Send an additional non-dust htlc from 1 to 0, and check the complaint
10681+
let (route, payment_hash, _, payment_secret) = get_route_and_payment_hash!(nodes[1], nodes[0], dust_limit * 2);
10682+
nodes[1].node.send_payment_with_route(route, payment_hash,
10683+
RecipientOnionFields::secret_only(payment_secret), PaymentId(payment_hash.0)).unwrap();
10684+
check_added_monitors!(nodes[1], 1);
10685+
let mut events = nodes[1].node.get_and_clear_pending_msg_events();
10686+
assert_eq!(events.len(), 1);
10687+
let payment_event = SendEvent::from_event(events.remove(0));
10688+
nodes[0].node.handle_update_add_htlc(nodes[1].node.get_our_node_id(), &payment_event.msgs[0]);
10689+
commitment_signed_dance!(nodes[0], nodes[1], payment_event.commitment_msg, false);
10690+
expect_pending_htlcs_forwardable!(nodes[0]);
10691+
expect_htlc_handling_failed_destinations!(nodes[0].node.get_and_clear_pending_events(), &[HTLCDestination::FailedPayment { payment_hash }]);
10692+
nodes[0].logger.assert_log("lightning::ln::channel",
10693+
format!("Cannot accept value that would put our total dust exposure at {} over the limit {} on counterparty commitment tx",
10694+
2535000, 2530000), 1);
10695+
check_added_monitors!(nodes[0], 1);
10696+
10697+
// Clear the failed htlc
10698+
let updates = get_htlc_update_msgs!(nodes[0], nodes[1].node.get_our_node_id());
10699+
assert!(updates.update_add_htlcs.is_empty());
10700+
assert!(updates.update_fulfill_htlcs.is_empty());
10701+
assert_eq!(updates.update_fail_htlcs.len(), 1);
10702+
assert!(updates.update_fail_malformed_htlcs.is_empty());
10703+
assert!(updates.update_fee.is_none());
10704+
nodes[1].node.handle_update_fail_htlc(nodes[0].node.get_our_node_id(), &updates.update_fail_htlcs[0]);
10705+
commitment_signed_dance!(nodes[1], nodes[0], updates.commitment_signed, false);
10706+
expect_payment_failed!(nodes[1], payment_hash, false);
10707+
10708+
assert_eq!(nodes[0].node.list_channels().len(), 1);
10709+
assert_eq!(nodes[1].node.list_channels().len(), 1);
10710+
assert_eq!(nodes[0].node.list_channels()[0].pending_inbound_htlcs.len(), 0);
10711+
assert_eq!(nodes[1].node.list_channels()[0].pending_outbound_htlcs.len(), 0);
10712+
10713+
// Send an additional non-dust htlc from 0 to 1 using the pre-calculated route above, and check the immediate complaint
10714+
unwrap_send_err!(nodes[0], nodes[0].node.send_payment_with_route(route_0_1, payment_hash_0_1,
10715+
RecipientOnionFields::secret_only(payment_secret_0_1), PaymentId(payment_hash_0_1.0)
10716+
), true, APIError::ChannelUnavailable { .. }, {});
10717+
nodes[0].logger.assert_log("lightning::ln::outbound_payment",
10718+
format!("Failed to send along path due to error: Channel unavailable: Cannot send more than our next-HTLC maximum - {} msat", 2325000), 1);
10719+
assert!(nodes[0].node.get_and_clear_pending_msg_events().is_empty());
10720+
10721+
assert_eq!(nodes[0].node.list_channels().len(), 1);
10722+
assert_eq!(nodes[1].node.list_channels().len(), 1);
10723+
assert_eq!(nodes[0].node.list_channels()[0].pending_inbound_htlcs.len(), 0);
10724+
assert_eq!(nodes[1].node.list_channels()[0].pending_outbound_htlcs.len(), 0);
10725+
1065810726
// At this point non-dust HTLCs are no longer accepted from node 0 -> 1, we also check that
1065910727
// such HTLCs can't be routed over the same channel either.
1066010728
create_announced_chan_between_nodes(&nodes, 2, 0);

0 commit comments

Comments
 (0)