33use crate :: events:: { ClosureReason , Event , HTLCHandlingFailureType , PaymentPurpose } ;
44use crate :: ln:: chan_utils:: {
55 self , commit_tx_fee_sat, commitment_tx_base_weight, second_stage_tx_fees_sat,
6- shared_anchor_script_pubkey, CommitmentTransaction , COMMITMENT_TX_WEIGHT_PER_HTLC ,
7- TRUC_CHILD_MAX_WEIGHT ,
6+ shared_anchor_script_pubkey, CommitmentTransaction , HTLCOutputInCommitment ,
7+ COMMITMENT_TX_WEIGHT_PER_HTLC , TRUC_CHILD_MAX_WEIGHT ,
88} ;
99use crate :: ln:: channel:: {
1010 get_holder_selected_channel_reserve_satoshis, Channel , ANCHOR_OUTPUT_VALUE_SATOSHI ,
@@ -888,7 +888,7 @@ pub fn do_test_fee_spike_buffer(cfg: Option<UserConfig>, htlc_fails: bool) {
888888
889889 // Build the remote commitment transaction so we can sign it, and then later use the
890890 // signature for the commitment_signed message.
891- let accepted_htlc_info = chan_utils :: HTLCOutputInCommitment {
891+ let accepted_htlc_info = HTLCOutputInCommitment {
892892 offered : false ,
893893 amount_msat : payment_amt_msat,
894894 cltv_expiry : htlc_cltv,
@@ -2143,7 +2143,7 @@ pub fn do_test_dust_limit_fee_accounting(can_afford: bool) {
21432143 let ( _payment_preimage, payment_hash, ..) =
21442144 route_payment ( & nodes[ 0 ] , & [ & nodes[ 1 ] ] , HTLC_AMT_SAT * 1000 ) ;
21452145 // Grab a snapshot of these HTLCs to manually build the commitment transaction later...
2146- let accepted_htlc = chan_utils :: HTLCOutputInCommitment {
2146+ let accepted_htlc = HTLCOutputInCommitment {
21472147 offered : false ,
21482148 amount_msat : HTLC_AMT_SAT * 1000 ,
21492149 // Hard-coded to match the expected value
@@ -2257,7 +2257,7 @@ pub fn do_test_dust_limit_fee_accounting(can_afford: bool) {
22572257 & channel_type,
22582258 ) ;
22592259
2260- let accepted_htlc_info = chan_utils :: HTLCOutputInCommitment {
2260+ let accepted_htlc_info = HTLCOutputInCommitment {
22612261 offered : false ,
22622262 amount_msat : HTLC_AMT_SAT * 1000 ,
22632263 cltv_expiry,
@@ -2838,21 +2838,30 @@ fn do_test_0reserve_no_outputs_legacy(no_outputs_case: LegacyChannelsNoOutputs)
28382838 return ;
28392839 }
28402840
2841+ let htlcs_in_commitment = vec ! [ HTLCOutputInCommitment {
2842+ offered: false ,
2843+ amount_msat: receiver_amount_msat,
2844+ cltv_expiry: htlc_cltv,
2845+ payment_hash,
2846+ transaction_output_index: Some ( 1 ) ,
2847+ } ] ;
2848+
28412849 manually_trigger_update_fail_htlc (
28422850 & nodes,
28432851 channel_id,
2844- channel_value_sat,
2852+ channel_value_sat * 1000 ,
28452853 dust_limit_satoshis,
2846- receiver_amount_msat,
2847- htlc_cltv,
28482854 payment_hash,
2855+ htlcs_in_commitment,
2856+ false ,
28492857 ) ;
28502858 }
28512859}
28522860
28532861fn manually_trigger_update_fail_htlc < ' a , ' b , ' c , ' d > (
2854- nodes : & ' a Vec < Node < ' b , ' c , ' d > > , channel_id : ChannelId , channel_value_sat : u64 ,
2855- dust_limit_satoshis : u64 , receiver_amount_msat : u64 , htlc_cltv : u32 , payment_hash : PaymentHash ,
2862+ nodes : & ' a Vec < Node < ' b , ' c , ' d > > , channel_id : ChannelId , value_to_self_msat : u64 ,
2863+ dust_limit_satoshis : u64 , payment_hash : PaymentHash ,
2864+ htlcs_in_commitment : Vec < HTLCOutputInCommitment > , can_afford_but_reserve_is_breached : bool ,
28562865) {
28572866 let node_a_id = nodes[ 0 ] . node . get_our_node_id ( ) ;
28582867 let node_b_id = nodes[ 1 ] . node . get_our_node_id ( ) ;
@@ -2864,45 +2873,36 @@ fn manually_trigger_update_fail_htlc<'a, 'b, 'c, 'd>(
28642873
28652874 let feerate_per_kw = get_feerate ! ( nodes[ 0 ] , nodes[ 1 ] , channel_id) ;
28662875
2867- const INITIAL_COMMITMENT_NUMBER : u64 = ( 1 << 48 ) - 1 ;
2868-
28692876 let ( local_secret, next_local_point) = {
28702877 let per_peer_state = nodes[ 0 ] . node . per_peer_state . read ( ) . unwrap ( ) ;
28712878 let chan_lock = per_peer_state. get ( & node_b_id) . unwrap ( ) . lock ( ) . unwrap ( ) ;
28722879 let local_chan =
28732880 chan_lock. channel_by_id . get ( & channel_id) . and_then ( Channel :: as_funded) . unwrap ( ) ;
28742881 let chan_signer = local_chan. get_signer ( ) ;
28752882 // Make the signer believe we validated another commitment, so we can release the secret
2883+ let commit_number = chan_signer. get_enforcement_state ( ) . last_holder_commitment ;
28762884 chan_signer. get_enforcement_state ( ) . last_holder_commitment -= 1 ;
28772885
28782886 (
2879- chan_signer. release_commitment_secret ( INITIAL_COMMITMENT_NUMBER ) . unwrap ( ) ,
2880- chan_signer. get_per_commitment_point ( INITIAL_COMMITMENT_NUMBER - 2 , & secp_ctx) . unwrap ( ) ,
2887+ chan_signer. release_commitment_secret ( commit_number ) . unwrap ( ) ,
2888+ chan_signer. get_per_commitment_point ( commit_number - 2 , & secp_ctx) . unwrap ( ) ,
28812889 )
28822890 } ;
2883- let remote_point = {
2891+ let ( remote_commit_number , remote_point) = {
28842892 let per_peer_lock;
28852893 let mut peer_state_lock;
28862894
28872895 let channel =
28882896 get_channel_ref ! ( nodes[ 1 ] , nodes[ 0 ] , per_peer_lock, peer_state_lock, channel_id) ;
28892897 let chan_signer = channel. as_funded ( ) . unwrap ( ) . get_signer ( ) ;
2890- chan_signer. get_per_commitment_point ( INITIAL_COMMITMENT_NUMBER - 1 , & secp_ctx) . unwrap ( )
2898+ let commit_number = chan_signer. get_enforcement_state ( ) . last_holder_commitment ;
2899+ let remote_point =
2900+ chan_signer. get_per_commitment_point ( commit_number - 1 , & secp_ctx) . unwrap ( ) ;
2901+ ( commit_number - 1 , remote_point)
28912902 } ;
28922903
28932904 // Build the remote commitment transaction so we can sign it, and then later use the
28942905 // signature for the commitment_signed message.
2895- let accepted_htlc_info = chan_utils:: HTLCOutputInCommitment {
2896- offered : false ,
2897- amount_msat : receiver_amount_msat,
2898- cltv_expiry : htlc_cltv,
2899- payment_hash,
2900- transaction_output_index : Some ( 1 ) ,
2901- } ;
2902-
2903- let local_chan_balance_msat = channel_value_sat * 1000 ;
2904- let commitment_number = INITIAL_COMMITMENT_NUMBER - 1 ;
2905-
29062906 let res = {
29072907 let per_peer_lock;
29082908 let mut peer_state_lock;
@@ -2913,12 +2913,12 @@ fn manually_trigger_update_fail_htlc<'a, 'b, 'c, 'd>(
29132913
29142914 let ( commitment_tx, _stats) = SpecTxBuilder { } . build_commitment_transaction (
29152915 false ,
2916- commitment_number ,
2916+ remote_commit_number ,
29172917 & remote_point,
29182918 & channel. funding ( ) . channel_transaction_parameters ,
29192919 & secp_ctx,
2920- local_chan_balance_msat ,
2921- vec ! [ accepted_htlc_info ] ,
2920+ value_to_self_msat ,
2921+ htlcs_in_commitment ,
29222922 feerate_per_kw,
29232923 dust_limit_satoshis,
29242924 & nodes[ 0 ] . logger ,
@@ -2969,11 +2969,13 @@ fn manually_trigger_update_fail_htlc<'a, 'b, 'c, 'd>(
29692969 } ,
29702970 _ => panic ! ( "Unexpected event" ) ,
29712971 } ;
2972- nodes[ 1 ] . logger . assert_log (
2973- "lightning::ln::channel" ,
2974- "Attempting to fail HTLC due to balance exhausted on remote commitment" . to_string ( ) ,
2975- 1 ,
2976- ) ;
2972+ let log_string =
2973+ if can_afford_but_reserve_is_breached {
2974+ String :: from ( "Attempting to fail HTLC due to fee spike buffer violation. Rebalancing is required." )
2975+ } else {
2976+ String :: from ( "Attempting to fail HTLC due to balance exhausted on remote commitment" )
2977+ } ;
2978+ nodes[ 1 ] . logger . assert_log ( "lightning::ln::channel" , log_string, 1 ) ;
29772979
29782980 check_added_monitors ( & nodes[ 1 ] , 3 ) ;
29792981}
@@ -3640,3 +3642,199 @@ fn test_0reserve_outbound_vs_available_capacity_outbound_htlc_limit() {
36403642 assert_eq ! ( node_1_details. outbound_capacity_msat, 0 ) ;
36413643 assert_eq ! ( nodes[ 1 ] . node. list_channels( ) [ 0 ] . next_outbound_htlc_limit_msat, 0 ) ;
36423644}
3645+
3646+ /// Make sure that we do not account for HTLCs going from non-dust to dust at the spiked feerate
3647+ /// when checking the fee spike buffer in `can_accept_incoming_htlc`. This is required to make sure
3648+ /// that we can afford *any* increase in the feerate between 1x to 2x, instead of checking whether
3649+ /// we can afford only the 2x increase in the feerate.
3650+ #[ xtest( feature = "_externalize_tests" ) ]
3651+ fn test_fail_cannot_afford_dust_htlcs_at_spike_multiple_if_nondust_at_base_feerate ( ) {
3652+ let mut config = test_default_channel_config ( ) ;
3653+ config. channel_handshake_config . negotiate_anchors_zero_fee_htlc_tx = false ;
3654+ config. channel_handshake_config . negotiate_anchor_zero_fee_commitments = false ;
3655+
3656+ let chanmon_cfgs = create_chanmon_cfgs ( 2 ) ;
3657+ let node_cfgs = create_node_cfgs ( 2 , & chanmon_cfgs) ;
3658+ config. channel_handshake_config . announced_channel_max_inbound_htlc_value_in_flight_percentage =
3659+ 100 ;
3660+
3661+ let channel_type = ChannelTypeFeatures :: only_static_remote_key ( ) ;
3662+
3663+ let node_chanmgrs = create_node_chanmgrs ( 2 , & node_cfgs, & [ Some ( config. clone ( ) ) , Some ( config) ] ) ;
3664+ let nodes = create_network ( 2 , & node_cfgs, & node_chanmgrs) ;
3665+
3666+ let node_a_id = nodes[ 0 ] . node . get_our_node_id ( ) ;
3667+ let _node_b_id = nodes[ 1 ] . node . get_our_node_id ( ) ;
3668+
3669+ const FEERATE : u32 = 253 ;
3670+ const MULTIPLE : u32 = FEE_SPIKE_BUFFER_FEE_INCREASE_MULTIPLE as u32 ;
3671+ const SPIKED_FEERATE : u32 = FEERATE * MULTIPLE ;
3672+ const DUST_LIMIT_MSAT : u64 = 354 * 1000 ;
3673+ const CHANNEL_VALUE_MSAT : u64 = 10_000 * 1000 ;
3674+ const NODE_0_VALUE_TO_SELF_MSAT : u64 = 5_000 * 1000 ;
3675+ const NODE_1_VALUE_TO_SELF_MSAT : u64 = 5_000 * 1000 ;
3676+ const CHANNEL_RESERVE_MSAT : u64 = 1_000 * 1_000 ;
3677+
3678+ let channel_id = create_announced_chan_between_nodes_with_value (
3679+ & nodes,
3680+ 0 ,
3681+ 1 ,
3682+ CHANNEL_VALUE_MSAT / 1000 ,
3683+ NODE_1_VALUE_TO_SELF_MSAT ,
3684+ )
3685+ . 2 ;
3686+ assert_eq ! ( nodes[ 0 ] . node. list_channels( ) [ 0 ] . channel_type. as_ref( ) . unwrap( ) , & channel_type) ;
3687+
3688+ // Find the HTLC amount that will be non-dust at the current feerate,
3689+ // but dust at the spiked feerate.
3690+ const SPIKED_DUST_HTLC_MSAT : u64 = 688 * 1000 ;
3691+ const HTLC_SPIKE_DUST_LIMIT_MSAT : u64 = 689 * 1000 ;
3692+ // When checking the fee spike buffer in `can_accept_incoming_htlc`, we check the remote
3693+ // commitment, hence inbound HTLCs will be offered HTLCs, and use the timeout dust limit.
3694+ let htlc_timeout_spike_tx_fee_msat =
3695+ second_stage_tx_fees_sat ( & channel_type, SPIKED_FEERATE ) . 1 * 1000 ;
3696+ assert_eq ! ( HTLC_SPIKE_DUST_LIMIT_MSAT , DUST_LIMIT_MSAT + htlc_timeout_spike_tx_fee_msat) ;
3697+
3698+ // Calculate here the dust limit at the current feerate so we know when node 0 cannot send
3699+ // any further non-dust HTLCs at the current feerate.
3700+ let htlc_timeout_tx_fee_msat = second_stage_tx_fees_sat ( & channel_type, FEERATE ) . 1 * 1000 ;
3701+ let htlc_dust_limit_msat = DUST_LIMIT_MSAT + htlc_timeout_tx_fee_msat;
3702+ // Make sure the HTLC will be non-dust at the current feerate
3703+ assert ! ( SPIKED_DUST_HTLC_MSAT > htlc_dust_limit_msat) ;
3704+
3705+ // Place a few non-dust HTLCs on the commitment, these HTLCs would get trimmed upon a 2x
3706+ // increase in the feerate.
3707+ let mut sent_htlcs_count: usize = 0 ;
3708+ let mut payment_hashes = Vec :: new ( ) ;
3709+ while nodes[ 0 ] . node . list_channels ( ) [ 0 ] . next_outbound_htlc_limit_msat >= htlc_dust_limit_msat {
3710+ let ( _preimage, hash, _secret, _id) =
3711+ route_payment ( & nodes[ 0 ] , & [ & nodes[ 1 ] ] , SPIKED_DUST_HTLC_MSAT ) ;
3712+ payment_hashes. push ( hash) ;
3713+ sent_htlcs_count += 1 ;
3714+ }
3715+ assert_eq ! ( sent_htlcs_count, 4 ) ;
3716+
3717+ // Check the outbound and available capacities
3718+ let node_0_outbound_capacity_msat = NODE_0_VALUE_TO_SELF_MSAT
3719+ - sent_htlcs_count as u64 * SPIKED_DUST_HTLC_MSAT
3720+ - CHANNEL_RESERVE_MSAT ;
3721+ let node_0_details = & nodes[ 0 ] . node . list_channels ( ) [ 0 ] ;
3722+ assert_eq ! ( node_0_details. outbound_capacity_msat, node_0_outbound_capacity_msat) ;
3723+ // Node 0 can now only send dust HTLCs, so we reserve the fees for a single additional
3724+ // inbound non-dust HTLC.
3725+ let min_reserved_fee_msat =
3726+ commit_tx_fee_sat ( SPIKED_FEERATE , sent_htlcs_count + 1 , & channel_type) * 1000 ;
3727+ let node_0_available_capacity_msat = node_0_outbound_capacity_msat - min_reserved_fee_msat;
3728+ assert_eq ! ( node_0_details. next_outbound_htlc_limit_msat, node_0_available_capacity_msat) ;
3729+
3730+ // Then send an identical, 5th non-dust HTLC, bypass the validation from the holder, and
3731+ // check that the counterparty fails it due to a fee spike buffer violation.
3732+
3733+ // First check the maths
3734+
3735+ // Node 0 can afford an exact 2x increase in the feerate
3736+ let spiked_commit_tx_fee_msat = commit_tx_fee_sat ( SPIKED_FEERATE , 0 , & channel_type) * 1000 ;
3737+ assert ! ( ( node_0_outbound_capacity_msat - SPIKED_DUST_HTLC_MSAT )
3738+ . checked_sub( spiked_commit_tx_fee_msat)
3739+ . is_some( ) ) ;
3740+ // Node 0 can afford a 5th non-dust HTLC at the current feerate, so `update_add_htlc`
3741+ // validation will pass.
3742+ let real_commit_tx_fee_msat = commit_tx_fee_sat ( FEERATE , 5 , & channel_type) * 1000 ;
3743+ assert ! ( ( node_0_outbound_capacity_msat - SPIKED_DUST_HTLC_MSAT )
3744+ . checked_sub( real_commit_tx_fee_msat)
3745+ . is_some( ) ) ;
3746+ // But we don't account for the HTLC trimming effect of the spike multiple feerate increase,
3747+ // so the 5th HTLC should be rejected at `can_accept_incoming_htlc`!
3748+ let expected_commit_tx_fee_msat = commit_tx_fee_sat ( SPIKED_FEERATE , 5 , & channel_type) * 1000 ;
3749+ assert ! ( ( node_0_outbound_capacity_msat - SPIKED_DUST_HTLC_MSAT )
3750+ . checked_sub( expected_commit_tx_fee_msat)
3751+ . is_none( ) ) ;
3752+
3753+ // Then run the experiment
3754+
3755+ let sender_amount_msat = node_0_available_capacity_msat;
3756+ let receiver_amount_msat = SPIKED_DUST_HTLC_MSAT ;
3757+ let ( route, payment_hash, _, payment_secret) =
3758+ get_route_and_payment_hash ! ( nodes[ 0 ] , nodes[ 1 ] , sender_amount_msat) ;
3759+ let secp_ctx = Secp256k1 :: new ( ) ;
3760+ let session_priv = SecretKey :: from_slice ( & [ 42 ; 32 ] ) . unwrap ( ) ;
3761+ let cur_height = nodes[ 0 ] . node . best_block . read ( ) . unwrap ( ) . height + 1 ;
3762+ let onion_keys = onion_utils:: construct_onion_keys ( & secp_ctx, & route. paths [ 0 ] , & session_priv) ;
3763+ let recipient_onion_fields =
3764+ RecipientOnionFields :: secret_only ( payment_secret, sender_amount_msat) ;
3765+ let ( onion_payloads, htlc_msat, htlc_cltv) = onion_utils:: test_build_onion_payloads (
3766+ & route. paths [ 0 ] ,
3767+ & recipient_onion_fields,
3768+ cur_height,
3769+ & None ,
3770+ None ,
3771+ None ,
3772+ )
3773+ . unwrap ( ) ;
3774+ assert_eq ! ( htlc_msat, sender_amount_msat) ;
3775+ let onion_packet =
3776+ onion_utils:: construct_onion_packet ( onion_payloads, onion_keys, [ 0 ; 32 ] , & payment_hash)
3777+ . unwrap ( ) ;
3778+ let msg = msgs:: UpdateAddHTLC {
3779+ channel_id,
3780+ htlc_id : sent_htlcs_count as u64 ,
3781+ amount_msat : receiver_amount_msat,
3782+ payment_hash,
3783+ cltv_expiry : htlc_cltv,
3784+ onion_routing_packet : onion_packet,
3785+ skimmed_fee_msat : None ,
3786+ blinding_point : None ,
3787+ hold_htlc : None ,
3788+ accountable : None ,
3789+ } ;
3790+
3791+ nodes[ 1 ] . node . handle_update_add_htlc ( node_a_id, & msg) ;
3792+
3793+ let htlcs_in_tx = vec ! [
3794+ HTLCOutputInCommitment {
3795+ offered: false ,
3796+ cltv_expiry: 81 ,
3797+ payment_hash: payment_hashes. iter( ) . find( |hash| hash. 0 [ 0 ] == 0x75 ) . unwrap( ) . clone( ) ,
3798+ amount_msat: 688_000 ,
3799+ transaction_output_index: Some ( 0 ) ,
3800+ } ,
3801+ HTLCOutputInCommitment {
3802+ offered: false ,
3803+ cltv_expiry: 81 ,
3804+ payment_hash: payment_hashes. iter( ) . find( |hash| hash. 0 [ 0 ] == 0x64 ) . unwrap( ) . clone( ) ,
3805+ amount_msat: 688_000 ,
3806+ transaction_output_index: Some ( 1 ) ,
3807+ } ,
3808+ HTLCOutputInCommitment {
3809+ offered: false ,
3810+ cltv_expiry: 81 ,
3811+ payment_hash,
3812+ amount_msat: 688_000 ,
3813+ transaction_output_index: Some ( 2 ) ,
3814+ } ,
3815+ HTLCOutputInCommitment {
3816+ offered: false ,
3817+ cltv_expiry: 81 ,
3818+ payment_hash: payment_hashes. iter( ) . find( |hash| hash. 0 [ 0 ] == 0x72 ) . unwrap( ) . clone( ) ,
3819+ amount_msat: 688_000 ,
3820+ transaction_output_index: Some ( 3 ) ,
3821+ } ,
3822+ HTLCOutputInCommitment {
3823+ offered: false ,
3824+ cltv_expiry: 81 ,
3825+ payment_hash: payment_hashes. iter( ) . find( |hash| hash. 0 [ 0 ] == 0x66 ) . unwrap( ) . clone( ) ,
3826+ amount_msat: 688_000 ,
3827+ transaction_output_index: Some ( 4 ) ,
3828+ } ,
3829+ ] ;
3830+
3831+ manually_trigger_update_fail_htlc (
3832+ & nodes,
3833+ channel_id,
3834+ NODE_0_VALUE_TO_SELF_MSAT ,
3835+ DUST_LIMIT_MSAT / 1000 ,
3836+ payment_hash,
3837+ htlcs_in_tx,
3838+ true ,
3839+ ) ;
3840+ }
0 commit comments