@@ -24,7 +24,7 @@ use crate::ln::types::ChannelId;
24
24
use crate::types::payment::{PaymentPreimage, PaymentSecret, PaymentHash};
25
25
use crate::ln::channel::{get_holder_selected_channel_reserve_satoshis, Channel, InboundV1Channel, OutboundV1Channel, COINBASE_MATURITY, CONCURRENT_INBOUND_HTLC_FEE_BUFFER, FEE_SPIKE_BUFFER_FEE_INCREASE_MULTIPLE, MIN_AFFORDABLE_HTLC_COUNT};
26
26
use crate::ln::channelmanager::{self, PaymentId, RAACommitmentOrder, RecipientOnionFields, BREAKDOWN_TIMEOUT, ENABLE_GOSSIP_TICKS, DISABLE_GOSSIP_TICKS, MIN_CLTV_EXPIRY_DELTA};
27
- use crate::ln::channel::{DISCONNECT_PEER_AWAITING_RESPONSE_TICKS, ChannelError};
27
+ use crate::ln::channel::{DISCONNECT_PEER_AWAITING_RESPONSE_TICKS, ChannelError, MIN_CHAN_DUST_LIMIT_SATOSHIS };
28
28
use crate::ln::{chan_utils, onion_utils};
29
29
use crate::ln::chan_utils::{commitment_tx_base_weight, COMMITMENT_TX_WEIGHT_PER_HTLC, OFFERED_HTLC_SCRIPT_WEIGHT, htlc_success_tx_weight, htlc_timeout_tx_weight, HTLCOutputInCommitment};
30
30
use crate::routing::gossip::{NetworkGraph, NetworkUpdate};
@@ -10750,6 +10750,204 @@ fn test_nondust_htlc_excess_fees_are_dust() {
10750
10750
expect_payment_failed_conditions(&nodes[2], payment_hash, false, PaymentFailedConditions::new());
10751
10751
}
10752
10752
10753
+ fn do_test_nondust_htlc_fees_dust_exposure_delta(features: ChannelTypeFeatures) {
10754
+ // Tests the increase in htlc dust exposure due to the excess mining fees of a single non-dust
10755
+ // HTLC on the counterparty commitment transaction, for both incoming and outgoing htlcs.
10756
+ //
10757
+ // Brings the dust exposure up to the base dust exposure using dust htlcs.
10758
+ // Sets the max dust exposure to 1msat below the expected dust exposure given an additional non-dust htlc.
10759
+ // Checks a failed payment for a non-dust htlc.
10760
+ // Sets the max dust exposure equal to the expected dust exposure given an additional non-dust htlc.
10761
+ // Checks a successful payment for a non-dust htlc.
10762
+ //
10763
+ // Runs this sequence for both directions.
10764
+
10765
+ let chanmon_cfgs = create_chanmon_cfgs(2);
10766
+
10767
+ const DEFAULT_FEERATE: u64 = 253;
10768
+ const HIGH_FEERATE: u64 = 275;
10769
+ const EXCESS_FEERATE: u64 = HIGH_FEERATE - DEFAULT_FEERATE;
10770
+
10771
+ const DUST_HTLC_COUNT: usize = 4;
10772
+ // Set dust htlcs to a satoshi value plus a non-zero msat amount to assert that
10773
+ // the dust accounting rounds transaction fees to the lower satoshi, but does not round dust htlc values.
10774
+ const DUST_HTLC_MSAT: u64 = 125_123;
10775
+ const BASE_DUST_EXPOSURE_MSAT: u64 = DUST_HTLC_COUNT as u64 * DUST_HTLC_MSAT;
10776
+
10777
+ const NON_DUST_HTLC_MSAT: u64 = 4_000_000;
10778
+
10779
+ {
10780
+ // Set the feerate of the channel funder above the `dust_exposure_limiting_feerate` of
10781
+ // the fundee. This delta means that the fundee will add the mining fees of the commitment and
10782
+ // htlc transactions in excess of its `dust_exposure_limiting_feerate` to its total dust htlc
10783
+ // exposure.
10784
+ let mut feerate_lock = chanmon_cfgs[0].fee_estimator.sat_per_kw.lock().unwrap();
10785
+ *feerate_lock = HIGH_FEERATE as u32;
10786
+ }
10787
+
10788
+ // Set `expected_dust_exposure_msat` to match the calculation in `FundedChannel::can_accept_incoming_htlc`
10789
+ // only_static_remote_key: 500_492 + 22 * (724 + 172) / 1000 * 1000 + 22 * 663 / 1000 * 1000 = 533_492
10790
+ // anchors_zero_htlc_fee: 500_492 + 22 * (1_124 + 172) / 1000 * 1000 = 528_492
10791
+ let mut expected_dust_exposure_msat = BASE_DUST_EXPOSURE_MSAT + EXCESS_FEERATE * (commitment_tx_base_weight(&features) + COMMITMENT_TX_WEIGHT_PER_HTLC) / 1000 * 1000;
10792
+ if features == ChannelTypeFeatures::only_static_remote_key() {
10793
+ expected_dust_exposure_msat += EXCESS_FEERATE * htlc_timeout_tx_weight(&features) / 1000 * 1000;
10794
+ assert_eq!(expected_dust_exposure_msat, 533_492);
10795
+ } else {
10796
+ assert_eq!(expected_dust_exposure_msat, 528_492);
10797
+ }
10798
+
10799
+ let mut default_config = test_default_channel_config();
10800
+ if features == ChannelTypeFeatures::anchors_zero_htlc_fee_and_dependencies() {
10801
+ default_config.channel_handshake_config.negotiate_anchors_zero_fee_htlc_tx = true;
10802
+ // in addition to the one above, this setting is also needed to create an anchor channel
10803
+ default_config.manually_accept_inbound_channels = true;
10804
+ }
10805
+
10806
+ // Set node 1's max dust htlc exposure to 1msat below `expected_dust_exposure_msat`
10807
+ let mut fixed_limit_config = default_config.clone();
10808
+ fixed_limit_config.channel_config.max_dust_htlc_exposure = MaxDustHTLCExposure::FixedLimitMsat(expected_dust_exposure_msat - 1);
10809
+
10810
+ let node_cfgs = create_node_cfgs(2, &chanmon_cfgs);
10811
+ let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[Some(default_config), Some(fixed_limit_config)]);
10812
+ let mut nodes = create_network(2, &node_cfgs, &node_chanmgrs);
10813
+
10814
+ let chan_id = create_chan_between_nodes_with_value(&nodes[0], &nodes[1], 100_000, 50_000_000).3;
10815
+
10816
+ let node_1_dust_buffer_feerate = {
10817
+ let per_peer_state = nodes[1].node.per_peer_state.read().unwrap();
10818
+ let chan_lock = per_peer_state.get(&nodes[0].node.get_our_node_id()).unwrap().lock().unwrap();
10819
+ let chan = chan_lock.channel_by_id.get(&chan_id).unwrap();
10820
+ chan.context().get_dust_buffer_feerate(None) as u64
10821
+ };
10822
+
10823
+ // Skip the router complaint when node 1 will attempt to pay node 0
10824
+ let (route_1_0, payment_hash_1_0, _, payment_secret_1_0) = get_route_and_payment_hash!(nodes[1], nodes[0], NON_DUST_HTLC_MSAT);
10825
+
10826
+ // Bring node 1's dust htlc exposure up to `BASE_DUST_EXPOSURE_MSAT`
10827
+ for _ in 0..DUST_HTLC_COUNT {
10828
+ route_payment(&nodes[0], &[&nodes[1]], DUST_HTLC_MSAT);
10829
+ }
10830
+
10831
+ assert_eq!(nodes[0].node.list_channels().len(), 1);
10832
+ assert_eq!(nodes[1].node.list_channels().len(), 1);
10833
+
10834
+ assert_eq!(nodes[0].node.list_channels()[0].pending_inbound_htlcs.len(), 0);
10835
+ assert_eq!(nodes[1].node.list_channels()[0].pending_outbound_htlcs.len(), 0);
10836
+ assert_eq!(nodes[0].node.list_channels()[0].pending_outbound_htlcs.len(), DUST_HTLC_COUNT);
10837
+ assert_eq!(nodes[1].node.list_channels()[0].pending_inbound_htlcs.len(), DUST_HTLC_COUNT);
10838
+
10839
+ // Send an additional non-dust htlc from 0 to 1, and check the complaint
10840
+ let (route, payment_hash, _, payment_secret) = get_route_and_payment_hash!(nodes[0], nodes[1], NON_DUST_HTLC_MSAT);
10841
+ nodes[0].node.send_payment_with_route(route, payment_hash,
10842
+ RecipientOnionFields::secret_only(payment_secret), PaymentId(payment_hash.0)).unwrap();
10843
+ check_added_monitors!(nodes[0], 1);
10844
+ let mut events = nodes[0].node.get_and_clear_pending_msg_events();
10845
+ assert_eq!(events.len(), 1);
10846
+ let payment_event = SendEvent::from_event(events.remove(0));
10847
+ nodes[1].node.handle_update_add_htlc(nodes[0].node.get_our_node_id(), &payment_event.msgs[0]);
10848
+ commitment_signed_dance!(nodes[1], nodes[0], payment_event.commitment_msg, false);
10849
+ expect_pending_htlcs_forwardable!(nodes[1]);
10850
+ expect_htlc_handling_failed_destinations!(nodes[1].node.get_and_clear_pending_events(), &[HTLCDestination::FailedPayment { payment_hash }]);
10851
+ nodes[1].logger.assert_log("lightning::ln::channel",
10852
+ format!("Cannot accept value that would put our total dust exposure at {} over the limit {} on counterparty commitment tx",
10853
+ expected_dust_exposure_msat, expected_dust_exposure_msat - 1), 1);
10854
+ check_added_monitors!(nodes[1], 1);
10855
+
10856
+ // Clear the failed htlc
10857
+ let updates = get_htlc_update_msgs!(nodes[1], nodes[0].node.get_our_node_id());
10858
+ assert!(updates.update_add_htlcs.is_empty());
10859
+ assert!(updates.update_fulfill_htlcs.is_empty());
10860
+ assert_eq!(updates.update_fail_htlcs.len(), 1);
10861
+ assert!(updates.update_fail_malformed_htlcs.is_empty());
10862
+ assert!(updates.update_fee.is_none());
10863
+ nodes[0].node.handle_update_fail_htlc(nodes[1].node.get_our_node_id(), &updates.update_fail_htlcs[0]);
10864
+ commitment_signed_dance!(nodes[0], nodes[1], updates.commitment_signed, false);
10865
+ expect_payment_failed!(nodes[0], payment_hash, false);
10866
+
10867
+ assert_eq!(nodes[0].node.list_channels().len(), 1);
10868
+ assert_eq!(nodes[1].node.list_channels().len(), 1);
10869
+
10870
+ assert_eq!(nodes[0].node.list_channels()[0].pending_inbound_htlcs.len(), 0);
10871
+ assert_eq!(nodes[1].node.list_channels()[0].pending_outbound_htlcs.len(), 0);
10872
+ assert_eq!(nodes[0].node.list_channels()[0].pending_outbound_htlcs.len(), DUST_HTLC_COUNT);
10873
+ assert_eq!(nodes[1].node.list_channels()[0].pending_inbound_htlcs.len(), DUST_HTLC_COUNT);
10874
+
10875
+ // Set node 1's max dust htlc exposure equal to the `expected_dust_exposure_msat`
10876
+ nodes[1].node.update_partial_channel_config(&nodes[0].node.get_our_node_id(), &[chan_id], &ChannelConfigUpdate {
10877
+ max_dust_htlc_exposure_msat: Some(MaxDustHTLCExposure::FixedLimitMsat(expected_dust_exposure_msat)),
10878
+ ..ChannelConfigUpdate::default()
10879
+ }).unwrap();
10880
+
10881
+ // Check a successful payment
10882
+ send_payment(&nodes[0], &[&nodes[1]], NON_DUST_HTLC_MSAT);
10883
+
10884
+ assert_eq!(nodes[0].node.list_channels().len(), 1);
10885
+ assert_eq!(nodes[1].node.list_channels().len(), 1);
10886
+
10887
+ assert_eq!(nodes[0].node.list_channels()[0].pending_inbound_htlcs.len(), 0);
10888
+ assert_eq!(nodes[1].node.list_channels()[0].pending_outbound_htlcs.len(), 0);
10889
+ assert_eq!(nodes[0].node.list_channels()[0].pending_outbound_htlcs.len(), DUST_HTLC_COUNT);
10890
+ assert_eq!(nodes[1].node.list_channels()[0].pending_inbound_htlcs.len(), DUST_HTLC_COUNT);
10891
+
10892
+ // The `expected_dust_exposure_msat` for the outbound htlc changes in the non-anchor case, as the htlc success and timeout transactions have different weights
10893
+ // only_static_remote_key: 500_492 + 22 * (724 + 172) / 1000 * 1000 + 22 * 703 / 1000 * 1000 = 534_492
10894
+ if features == ChannelTypeFeatures::only_static_remote_key() {
10895
+ expected_dust_exposure_msat = BASE_DUST_EXPOSURE_MSAT + EXCESS_FEERATE * (commitment_tx_base_weight(&features) + COMMITMENT_TX_WEIGHT_PER_HTLC) / 1000 * 1000 + EXCESS_FEERATE * htlc_success_tx_weight(&features) / 1000 * 1000;
10896
+ assert_eq!(expected_dust_exposure_msat, 534_492);
10897
+ } else {
10898
+ assert_eq!(expected_dust_exposure_msat, 528_492);
10899
+ }
10900
+
10901
+ // Set node 1's max dust htlc exposure to 1msat below `expected_dust_exposure_msat`
10902
+ nodes[1].node.update_partial_channel_config(&nodes[0].node.get_our_node_id(), &[chan_id], &ChannelConfigUpdate {
10903
+ max_dust_htlc_exposure_msat: Some(MaxDustHTLCExposure::FixedLimitMsat(expected_dust_exposure_msat - 1)),
10904
+ ..ChannelConfigUpdate::default()
10905
+ }).unwrap();
10906
+
10907
+ // Send an additional non-dust htlc from 1 to 0 using the pre-calculated route above, and check the immediate complaint
10908
+ unwrap_send_err!(nodes[1], nodes[1].node.send_payment_with_route(route_1_0, payment_hash_1_0,
10909
+ RecipientOnionFields::secret_only(payment_secret_1_0), PaymentId(payment_hash_1_0.0)
10910
+ ), true, APIError::ChannelUnavailable { .. }, {});
10911
+ let dust_limit = if features == ChannelTypeFeatures::only_static_remote_key() {
10912
+ MIN_CHAN_DUST_LIMIT_SATOSHIS * 1000 + htlc_success_tx_weight(&features) * node_1_dust_buffer_feerate / 1000 * 1000
10913
+ } else {
10914
+ MIN_CHAN_DUST_LIMIT_SATOSHIS * 1000
10915
+ };
10916
+ nodes[1].logger.assert_log("lightning::ln::outbound_payment",
10917
+ format!("Failed to send along path due to error: Channel unavailable: Cannot send more than our next-HTLC maximum - {} msat", dust_limit), 1);
10918
+ assert!(nodes[1].node.get_and_clear_pending_msg_events().is_empty());
10919
+
10920
+ assert_eq!(nodes[0].node.list_channels().len(), 1);
10921
+ assert_eq!(nodes[1].node.list_channels().len(), 1);
10922
+
10923
+ assert_eq!(nodes[0].node.list_channels()[0].pending_inbound_htlcs.len(), 0);
10924
+ assert_eq!(nodes[1].node.list_channels()[0].pending_outbound_htlcs.len(), 0);
10925
+ assert_eq!(nodes[0].node.list_channels()[0].pending_outbound_htlcs.len(), DUST_HTLC_COUNT);
10926
+ assert_eq!(nodes[1].node.list_channels()[0].pending_inbound_htlcs.len(), DUST_HTLC_COUNT);
10927
+
10928
+ // Set node 1's max dust htlc exposure equal to `expected_dust_exposure_msat`
10929
+ nodes[1].node.update_partial_channel_config(&nodes[0].node.get_our_node_id(), &[chan_id], &ChannelConfigUpdate {
10930
+ max_dust_htlc_exposure_msat: Some(MaxDustHTLCExposure::FixedLimitMsat(expected_dust_exposure_msat)),
10931
+ ..ChannelConfigUpdate::default()
10932
+ }).unwrap();
10933
+
10934
+ // Check a successful payment
10935
+ send_payment(&nodes[1], &[&nodes[0]], NON_DUST_HTLC_MSAT);
10936
+
10937
+ assert_eq!(nodes[0].node.list_channels().len(), 1);
10938
+ assert_eq!(nodes[1].node.list_channels().len(), 1);
10939
+
10940
+ assert_eq!(nodes[0].node.list_channels()[0].pending_inbound_htlcs.len(), 0);
10941
+ assert_eq!(nodes[1].node.list_channels()[0].pending_outbound_htlcs.len(), 0);
10942
+ assert_eq!(nodes[0].node.list_channels()[0].pending_outbound_htlcs.len(), DUST_HTLC_COUNT);
10943
+ assert_eq!(nodes[1].node.list_channels()[0].pending_inbound_htlcs.len(), DUST_HTLC_COUNT);
10944
+ }
10945
+
10946
+ #[test]
10947
+ fn test_nondust_htlc_fees_dust_exposure_delta() {
10948
+ do_test_nondust_htlc_fees_dust_exposure_delta(ChannelTypeFeatures::only_static_remote_key());
10949
+ do_test_nondust_htlc_fees_dust_exposure_delta(ChannelTypeFeatures::anchors_zero_htlc_fee_and_dependencies());
10950
+ }
10753
10951
10754
10952
#[test]
10755
10953
fn test_non_final_funding_tx() {
0 commit comments