@@ -9304,3 +9304,175 @@ fn do_test_splice_out_initiator_reserve_breach_zero_fee_commitments(
93049304 acceptor. logger . assert_log ( "lightning::ln::channelmanager" , cannot_splice_out, 1 ) ;
93059305 }
93069306}
9307+
9308+ #[ test]
9309+ fn test_splice_out_maximum_on_both_commitments_dust_on_fundee_commitment ( ) {
9310+ use crate :: ln:: htlc_reserve_unit_tests:: setup_0reserve_no_outputs_channels;
9311+
9312+ let chanmon_cfgs = create_chanmon_cfgs ( 2 ) ;
9313+ let node_cfgs = create_node_cfgs ( 2 , & chanmon_cfgs) ;
9314+ let mut config = test_default_channel_config ( ) ;
9315+ config. channel_handshake_config . announced_channel_max_inbound_htlc_value_in_flight_percentage =
9316+ 100 ;
9317+ let node_chanmgrs = create_node_chanmgrs ( 2 , & node_cfgs, & [ Some ( config. clone ( ) ) , Some ( config) ] ) ;
9318+ let nodes = create_network ( 2 , & node_cfgs, & node_chanmgrs) ;
9319+
9320+ const CHANNEL_VALUE_SAT : u64 = 100_000 ;
9321+ const FEERATE : u32 = 253 ;
9322+ const TOTAL_ANCHORS_SAT : u64 = 2 * 330 ;
9323+ const NODE_0_DUST_LIMIT_SAT : u64 = 354 ;
9324+ const NODE_1_DUST_LIMIT_SAT : u64 = 10_000 ;
9325+
9326+ let ( channel_id, _transaction) =
9327+ setup_0reserve_no_outputs_channels ( & nodes, CHANNEL_VALUE_SAT , NODE_0_DUST_LIMIT_SAT ) ;
9328+
9329+ {
9330+ let per_peer_state_lock;
9331+ let mut peer_state_lock;
9332+ let chan =
9333+ get_channel_ref ! ( nodes[ 0 ] , nodes[ 1 ] , per_peer_state_lock, peer_state_lock, channel_id) ;
9334+ chan. context_mut ( ) . counterparty_dust_limit_satoshis = NODE_1_DUST_LIMIT_SAT ;
9335+ assert_eq ! ( chan. context( ) . holder_dust_limit_satoshis, NODE_0_DUST_LIMIT_SAT ) ;
9336+ assert_eq ! ( chan. funding( ) . holder_selected_channel_reserve_satoshis, 0 ) ;
9337+ assert_eq ! ( chan. funding( ) . counterparty_selected_channel_reserve_satoshis, Some ( 0 ) ) ;
9338+ }
9339+
9340+ {
9341+ let per_peer_state_lock;
9342+ let mut peer_state_lock;
9343+ let chan =
9344+ get_channel_ref ! ( nodes[ 1 ] , nodes[ 0 ] , per_peer_state_lock, peer_state_lock, channel_id) ;
9345+ chan. context_mut ( ) . holder_dust_limit_satoshis = NODE_1_DUST_LIMIT_SAT ;
9346+ assert_eq ! ( chan. context( ) . counterparty_dust_limit_satoshis, NODE_0_DUST_LIMIT_SAT ) ;
9347+ assert_eq ! ( chan. funding( ) . holder_selected_channel_reserve_satoshis, 0 ) ;
9348+ assert_eq ! ( chan. funding( ) . counterparty_selected_channel_reserve_satoshis, Some ( 0 ) ) ;
9349+ }
9350+
9351+ let details = & nodes[ 0 ] . node . list_channels ( ) [ 0 ] ;
9352+ let channel_type = details. channel_type . clone ( ) . unwrap ( ) ;
9353+ assert_eq ! ( channel_type, ChannelTypeFeatures :: anchors_zero_htlc_fee_and_dependencies( ) ) ;
9354+
9355+ // This HTLC is only present on node 0's commitment
9356+ const SNEAKY_HTLC_SAT : u64 = 5_000 ;
9357+
9358+ let ( _, payment_hash, ..) = route_payment ( & nodes[ 0 ] , & [ & nodes[ 1 ] ] , SNEAKY_HTLC_SAT * 1000 ) ;
9359+
9360+ let node_0_details = & nodes[ 0 ] . node . list_channels ( ) [ 0 ] ;
9361+ let reserved_fee_sat = chan_utils:: commit_tx_fee_sat ( FEERATE , 0 , & channel_type) ;
9362+ let expected_next_splice_out_maximum_sat = CHANNEL_VALUE_SAT
9363+ - SNEAKY_HTLC_SAT
9364+ - TOTAL_ANCHORS_SAT
9365+ - reserved_fee_sat
9366+ - NODE_1_DUST_LIMIT_SAT ;
9367+ assert_eq ! ( node_0_details. next_splice_out_maximum_sat, expected_next_splice_out_maximum_sat) ;
9368+ let node_1_details = & nodes[ 1 ] . node . list_channels ( ) [ 0 ] ;
9369+ assert_eq ! ( node_1_details. next_splice_out_maximum_sat, 0 ) ;
9370+
9371+ fail_payment ( & nodes[ 0 ] , & [ & nodes[ 1 ] ] , payment_hash) ;
9372+
9373+ let details = & nodes[ 0 ] . node . list_channels ( ) [ 0 ] ;
9374+ let reserved_fee_sat = chan_utils:: commit_tx_fee_sat ( FEERATE , 2 , & channel_type) ;
9375+ let expected_available_capacity_sat = CHANNEL_VALUE_SAT - TOTAL_ANCHORS_SAT - reserved_fee_sat;
9376+ assert_eq ! ( details. next_outbound_htlc_limit_msat, expected_available_capacity_sat * 1000 ) ;
9377+ let node_0_payment_sat = expected_available_capacity_sat;
9378+ send_payment ( & nodes[ 0 ] , & [ & nodes[ 1 ] ] , node_0_payment_sat * 1000 ) ;
9379+
9380+ // Make sure the local output is now gone from node 1's commitment
9381+ assert ! ( TOTAL_ANCHORS_SAT + reserved_fee_sat < NODE_1_DUST_LIMIT_SAT ) ;
9382+
9383+ let details = & nodes[ 1 ] . node . list_channels ( ) [ 0 ] ;
9384+ let expected_next_splice_out_maximum_sat = node_0_payment_sat - NODE_1_DUST_LIMIT_SAT ;
9385+ assert_eq ! ( details. next_splice_out_maximum_sat, expected_next_splice_out_maximum_sat) ;
9386+
9387+ let details = & nodes[ 0 ] . node . list_channels ( ) [ 0 ] ;
9388+ let reserved_fee_sat = chan_utils:: commit_tx_fee_sat ( FEERATE , 1 , & channel_type) ;
9389+ let expected_next_splice_out_maximum_sat =
9390+ CHANNEL_VALUE_SAT - node_0_payment_sat - TOTAL_ANCHORS_SAT - reserved_fee_sat;
9391+ assert_eq ! ( details. next_splice_out_maximum_sat, expected_next_splice_out_maximum_sat) ;
9392+ }
9393+
9394+ #[ test]
9395+ fn test_splice_out_maximum_on_both_commitments_dust_on_funder_commitment ( ) {
9396+ use crate :: ln:: htlc_reserve_unit_tests:: setup_0reserve_no_outputs_channels;
9397+
9398+ let chanmon_cfgs = create_chanmon_cfgs ( 2 ) ;
9399+ let node_cfgs = create_node_cfgs ( 2 , & chanmon_cfgs) ;
9400+ let mut config = test_default_channel_config ( ) ;
9401+ config. channel_handshake_config . announced_channel_max_inbound_htlc_value_in_flight_percentage =
9402+ 100 ;
9403+ let node_chanmgrs = create_node_chanmgrs ( 2 , & node_cfgs, & [ Some ( config. clone ( ) ) , Some ( config) ] ) ;
9404+ let nodes = create_network ( 2 , & node_cfgs, & node_chanmgrs) ;
9405+
9406+ const CHANNEL_VALUE_SAT : u64 = 100_000 ;
9407+ const FEERATE : u32 = 253 ;
9408+ const TOTAL_ANCHORS_SAT : u64 = 2 * 330 ;
9409+ const NODE_0_DUST_LIMIT_SAT : u64 = 10_000 ;
9410+ const NODE_1_DUST_LIMIT_SAT : u64 = 354 ;
9411+
9412+ let ( channel_id, _transaction) =
9413+ setup_0reserve_no_outputs_channels ( & nodes, CHANNEL_VALUE_SAT , NODE_1_DUST_LIMIT_SAT ) ;
9414+
9415+ {
9416+ let per_peer_state_lock;
9417+ let mut peer_state_lock;
9418+ let chan =
9419+ get_channel_ref ! ( nodes[ 0 ] , nodes[ 1 ] , per_peer_state_lock, peer_state_lock, channel_id) ;
9420+ chan. context_mut ( ) . holder_dust_limit_satoshis = NODE_0_DUST_LIMIT_SAT ;
9421+ assert_eq ! ( chan. context( ) . counterparty_dust_limit_satoshis, NODE_1_DUST_LIMIT_SAT ) ;
9422+ assert_eq ! ( chan. funding( ) . holder_selected_channel_reserve_satoshis, 0 ) ;
9423+ assert_eq ! ( chan. funding( ) . counterparty_selected_channel_reserve_satoshis, Some ( 0 ) ) ;
9424+ }
9425+
9426+ {
9427+ let per_peer_state_lock;
9428+ let mut peer_state_lock;
9429+ let chan =
9430+ get_channel_ref ! ( nodes[ 1 ] , nodes[ 0 ] , per_peer_state_lock, peer_state_lock, channel_id) ;
9431+ chan. context_mut ( ) . counterparty_dust_limit_satoshis = NODE_0_DUST_LIMIT_SAT ;
9432+ assert_eq ! ( chan. context( ) . holder_dust_limit_satoshis, NODE_1_DUST_LIMIT_SAT ) ;
9433+ assert_eq ! ( chan. funding( ) . holder_selected_channel_reserve_satoshis, 0 ) ;
9434+ assert_eq ! ( chan. funding( ) . counterparty_selected_channel_reserve_satoshis, Some ( 0 ) ) ;
9435+ }
9436+
9437+ let details = & nodes[ 0 ] . node . list_channels ( ) [ 0 ] ;
9438+ let channel_type = details. channel_type . clone ( ) . unwrap ( ) ;
9439+ assert_eq ! ( channel_type, ChannelTypeFeatures :: anchors_zero_htlc_fee_and_dependencies( ) ) ;
9440+
9441+ // This HTLC is only present on node 1's commitment
9442+ const SNEAKY_HTLC_SAT : u64 = 5_000 ;
9443+
9444+ let ( _, payment_hash, ..) = route_payment ( & nodes[ 0 ] , & [ & nodes[ 1 ] ] , SNEAKY_HTLC_SAT * 1000 ) ;
9445+
9446+ let node_0_details = & nodes[ 0 ] . node . list_channels ( ) [ 0 ] ;
9447+ let reserved_fee_sat = chan_utils:: commit_tx_fee_sat ( FEERATE , 0 , & channel_type) ;
9448+ let expected_next_splice_out_maximum_sat = CHANNEL_VALUE_SAT
9449+ - SNEAKY_HTLC_SAT
9450+ - TOTAL_ANCHORS_SAT
9451+ - reserved_fee_sat
9452+ - NODE_0_DUST_LIMIT_SAT ;
9453+ assert_eq ! ( node_0_details. next_splice_out_maximum_sat, expected_next_splice_out_maximum_sat) ;
9454+ let node_1_details = & nodes[ 1 ] . node . list_channels ( ) [ 0 ] ;
9455+ assert_eq ! ( node_1_details. next_splice_out_maximum_sat, 0 ) ;
9456+
9457+ fail_payment ( & nodes[ 0 ] , & [ & nodes[ 1 ] ] , payment_hash) ;
9458+
9459+ let details = & nodes[ 0 ] . node . list_channels ( ) [ 0 ] ;
9460+ let reserved_fee_sat = chan_utils:: commit_tx_fee_sat ( FEERATE , 2 , & channel_type) ;
9461+ let expected_available_capacity_sat = CHANNEL_VALUE_SAT - TOTAL_ANCHORS_SAT - reserved_fee_sat;
9462+ assert_eq ! ( details. next_outbound_htlc_limit_msat, expected_available_capacity_sat * 1000 ) ;
9463+ let node_0_payment_sat = expected_available_capacity_sat;
9464+ send_payment ( & nodes[ 0 ] , & [ & nodes[ 1 ] ] , node_0_payment_sat * 1000 ) ;
9465+
9466+ // Make sure the local output is now gone from node 0's commitment
9467+ assert ! ( TOTAL_ANCHORS_SAT + reserved_fee_sat < NODE_0_DUST_LIMIT_SAT ) ;
9468+
9469+ let details = & nodes[ 1 ] . node . list_channels ( ) [ 0 ] ;
9470+ let expected_next_splice_out_maximum_sat = node_0_payment_sat - NODE_0_DUST_LIMIT_SAT ;
9471+ assert_eq ! ( details. next_splice_out_maximum_sat, expected_next_splice_out_maximum_sat) ;
9472+
9473+ let details = & nodes[ 0 ] . node . list_channels ( ) [ 0 ] ;
9474+ let reserved_fee_sat = chan_utils:: commit_tx_fee_sat ( FEERATE , 1 , & channel_type) ;
9475+ let expected_next_splice_out_maximum_sat =
9476+ CHANNEL_VALUE_SAT - node_0_payment_sat - TOTAL_ANCHORS_SAT - reserved_fee_sat;
9477+ assert_eq ! ( details. next_splice_out_maximum_sat, expected_next_splice_out_maximum_sat) ;
9478+ }
0 commit comments