@@ -6305,3 +6305,76 @@ fn test_splice_revalidation_at_quiescence() {
63056305
63066306 expect_splice_failed_events ( & nodes[ 0 ] , & channel_id, contribution) ;
63076307}
6308+
6309+ #[ test]
6310+ fn test_splice_rbf_rejects_low_feerate_after_several_attempts ( ) {
6311+ // After several RBF attempts, the counterparty's RBF feerate must be high enough to
6312+ // confirm (per the fee estimator). Early attempts at low feerates are accepted, but
6313+ // once the threshold is crossed and the fee estimator expects a higher feerate, the
6314+ // attempt is rejected.
6315+ let chanmon_cfgs = create_chanmon_cfgs ( 2 ) ;
6316+ let node_cfgs = create_node_cfgs ( 2 , & chanmon_cfgs) ;
6317+ let node_chanmgrs = create_node_chanmgrs ( 2 , & node_cfgs, & [ None , None ] ) ;
6318+ let nodes = create_network ( 2 , & node_cfgs, & node_chanmgrs) ;
6319+
6320+ let node_id_0 = nodes[ 0 ] . node . get_our_node_id ( ) ;
6321+ let node_id_1 = nodes[ 1 ] . node . get_our_node_id ( ) ;
6322+
6323+ let initial_channel_value_sat = 100_000 ;
6324+ let ( _, _, channel_id, _) =
6325+ create_announced_chan_between_nodes_with_value ( & nodes, 0 , 1 , initial_channel_value_sat, 0 ) ;
6326+
6327+ let added_value = Amount :: from_sat ( 50_000 ) ;
6328+ provide_utxo_reserves ( & nodes, 2 , added_value * 2 ) ;
6329+
6330+ // Round 0: Initial splice-in at floor feerate (253).
6331+ let funding_contribution = do_initiate_splice_in ( & nodes[ 0 ] , & nodes[ 1 ] , channel_id, added_value) ;
6332+ let ( _, new_funding_script) =
6333+ splice_channel ( & nodes[ 0 ] , & nodes[ 1 ] , channel_id, funding_contribution) ;
6334+
6335+ // Feerate progression: 253 → 264 → 275 → 287 → 300
6336+ let feerate_1 = ( FEERATE_FLOOR_SATS_PER_KW as u64 * 25 ) . div_ceil ( 24 ) ;
6337+ let feerate_2 = ( feerate_1 * 25 ) . div_ceil ( 24 ) ;
6338+ let feerate_3 = ( feerate_2 * 25 ) . div_ceil ( 24 ) ;
6339+ let feerate_4 = ( feerate_3 * 25 ) . div_ceil ( 24 ) ;
6340+
6341+ // Rounds 1-3: RBF at minimum bump. Accepted (at or below threshold).
6342+ for feerate in [ feerate_1, feerate_2, feerate_3] {
6343+ provide_utxo_reserves ( & nodes, 2 , added_value * 2 ) ;
6344+ let rbf_feerate = FeeRate :: from_sat_per_kwu ( feerate) ;
6345+ let contribution =
6346+ do_initiate_rbf_splice_in ( & nodes[ 0 ] , & nodes[ 1 ] , channel_id, added_value, rbf_feerate) ;
6347+ complete_rbf_handshake ( & nodes[ 0 ] , & nodes[ 1 ] ) ;
6348+ complete_interactive_funding_negotiation (
6349+ & nodes[ 0 ] ,
6350+ & nodes[ 1 ] ,
6351+ channel_id,
6352+ contribution,
6353+ new_funding_script. clone ( ) ,
6354+ ) ;
6355+ let ( _, splice_locked) = sign_interactive_funding_tx ( & nodes[ 0 ] , & nodes[ 1 ] , false ) ;
6356+ assert ! ( splice_locked. is_none( ) ) ;
6357+ expect_splice_pending_event ( & nodes[ 0 ] , & node_id_1) ;
6358+ expect_splice_pending_event ( & nodes[ 1 ] , & node_id_0) ;
6359+ }
6360+
6361+ // Now 4 negotiated candidates (round 0 + rounds 1-3). Bump the fee estimator on node 1
6362+ // (the RBF receiver) so the next minimum RBF feerate (300) is below it.
6363+ let high_feerate = 1000 ;
6364+ * chanmon_cfgs[ 1 ] . fee_estimator . sat_per_kw . lock ( ) . unwrap ( ) = high_feerate;
6365+
6366+ // Round 4: RBF at minimum bump (300). Should be rejected because 300 < 1000.
6367+ provide_utxo_reserves ( & nodes, 2 , added_value * 2 ) ;
6368+ let rbf_feerate_3 = FeeRate :: from_sat_per_kwu ( feerate_4) ;
6369+ let _contribution =
6370+ do_initiate_rbf_splice_in ( & nodes[ 0 ] , & nodes[ 1 ] , channel_id, added_value, rbf_feerate_3) ;
6371+ let stfu_0 = get_event_msg ! ( nodes[ 0 ] , MessageSendEvent :: SendStfu , node_id_1) ;
6372+ nodes[ 1 ] . node . handle_stfu ( node_id_0, & stfu_0) ;
6373+ let stfu_1 = get_event_msg ! ( nodes[ 1 ] , MessageSendEvent :: SendStfu , node_id_0) ;
6374+ nodes[ 0 ] . node . handle_stfu ( node_id_1, & stfu_1) ;
6375+
6376+ // Node 0 sends tx_init_rbf. Node 1 rejects the low feerate after the threshold.
6377+ let tx_init_rbf = get_event_msg ! ( nodes[ 0 ] , MessageSendEvent :: SendTxInitRbf , node_id_1) ;
6378+ nodes[ 1 ] . node . handle_tx_init_rbf ( node_id_0, & tx_init_rbf) ;
6379+ get_event_msg ! ( nodes[ 1 ] , MessageSendEvent :: SendTxAbort , node_id_0) ;
6380+ }
0 commit comments