@@ -619,3 +619,103 @@ fn test_shutdown_script_segwit_but_not_anysegwit() {
619
619
}
620
620
check_added_monitors ! ( nodes[ 0 ] , 1 ) ;
621
621
}
622
+
623
+ fn do_test_closing_signed_reinit_timeout ( timeout_step : u8 ) {
624
+ // The range-based closing signed negotiation allows the funder to restart the process with a
625
+ // new range if the previous range did not overlap. This allows implementations to request user
626
+ // intervention allowing users to enter a new fee range. We do not implement the sending side
627
+ // of this, instead opting to allow users to enter an explicit "willing to pay up to X to avoid
628
+ // force-closing" value and relying on that instead.
629
+ //
630
+ // Here we run test the fundee side of that restart mechanism, implementing the funder side of
631
+ // it manually.
632
+ let chanmon_cfgs = create_chanmon_cfgs ( 2 ) ;
633
+ let node_cfgs = create_node_cfgs ( 2 , & chanmon_cfgs) ;
634
+ let node_chanmgrs = create_node_chanmgrs ( 2 , & node_cfgs, & [ None , None ] ) ;
635
+ let mut nodes = create_network ( 2 , & node_cfgs, & node_chanmgrs) ;
636
+ let chan_id = create_announced_chan_between_nodes ( & nodes, 0 , 1 , InitFeatures :: known ( ) , InitFeatures :: known ( ) ) . 2 ;
637
+
638
+ send_payment ( & nodes[ 0 ] , & [ & nodes[ 1 ] ] , 8_000_000 ) ;
639
+
640
+ nodes[ 0 ] . node . close_channel ( & chan_id, None ) . unwrap ( ) ;
641
+ let node_0_shutdown = get_event_msg ! ( nodes[ 0 ] , MessageSendEvent :: SendShutdown , nodes[ 1 ] . node. get_our_node_id( ) ) ;
642
+ nodes[ 1 ] . node . handle_shutdown ( & nodes[ 0 ] . node . get_our_node_id ( ) , & InitFeatures :: known ( ) , & node_0_shutdown) ;
643
+ let node_1_shutdown = get_event_msg ! ( nodes[ 1 ] , MessageSendEvent :: SendShutdown , nodes[ 0 ] . node. get_our_node_id( ) ) ;
644
+ nodes[ 0 ] . node . handle_shutdown ( & nodes[ 1 ] . node . get_our_node_id ( ) , & InitFeatures :: known ( ) , & node_1_shutdown) ;
645
+
646
+ {
647
+ // Now we set nodes[1] to require a relatively high feerate for closing. This should result
648
+ // in it rejecting nodes[0]'s initial closing_signed, giving nodes[0] a chance to try
649
+ // again.
650
+ let mut feerate_lock = chanmon_cfgs[ 1 ] . fee_estimator . sat_per_kw . lock ( ) . unwrap ( ) ;
651
+ * feerate_lock *= 10 ;
652
+ }
653
+
654
+ let mut node_0_closing_signed = get_event_msg ! ( nodes[ 0 ] , MessageSendEvent :: SendClosingSigned , nodes[ 1 ] . node. get_our_node_id( ) ) ;
655
+ assert ! ( node_0_closing_signed. fee_satoshis <= 500 ) ;
656
+
657
+ if timeout_step != 0 {
658
+ nodes[ 1 ] . node . handle_closing_signed ( & nodes[ 0 ] . node . get_our_node_id ( ) , & node_0_closing_signed) ;
659
+ // At this point nodes[1] should send back a warning message indicating it disagrees with the
660
+ // given channel-closing fee. Currently we do not implement warning messages so instead we
661
+ // remain silent here.
662
+ assert ! ( nodes[ 1 ] . node. get_and_clear_pending_msg_events( ) . is_empty( ) ) ;
663
+
664
+ // Now deliver a mutated closing_signed indicating a higher acceptable fee range, which
665
+ // nodes[1] should happily accept and respond to.
666
+ node_0_closing_signed. fee_range . as_mut ( ) . unwrap ( ) . max_fee_satoshis *= 10 ;
667
+ {
668
+ let mut lock;
669
+ get_channel_ref ! ( nodes[ 0 ] , lock, chan_id) . closing_fee_limits . as_mut ( ) . unwrap ( ) . 1 *= 10 ;
670
+ }
671
+ nodes[ 1 ] . node . handle_closing_signed ( & nodes[ 0 ] . node . get_our_node_id ( ) , & node_0_closing_signed) ;
672
+ let node_1_closing_signed = get_event_msg ! ( nodes[ 1 ] , MessageSendEvent :: SendClosingSigned , nodes[ 0 ] . node. get_our_node_id( ) ) ;
673
+ nodes[ 0 ] . node . handle_closing_signed ( & nodes[ 1 ] . node . get_our_node_id ( ) , & node_1_closing_signed) ;
674
+ let node_0_2nd_closing_signed = get_closing_signed_broadcast ! ( nodes[ 0 ] . node, nodes[ 1 ] . node. get_our_node_id( ) ) ;
675
+ if timeout_step > 1 {
676
+ nodes[ 1 ] . node . handle_closing_signed ( & nodes[ 0 ] . node . get_our_node_id ( ) , & node_0_2nd_closing_signed. 1 . unwrap ( ) ) ;
677
+ }
678
+ }
679
+
680
+ if timeout_step <= 1 {
681
+ assert ! ( nodes[ 1 ] . tx_broadcaster. txn_broadcasted. lock( ) . unwrap( ) . is_empty( ) ) ;
682
+ } else {
683
+ assert_eq ! ( nodes[ 1 ] . tx_broadcaster. txn_broadcasted. lock( ) . unwrap( ) . len( ) , 1 ) ;
684
+ }
685
+
686
+ nodes[ 1 ] . node . timer_tick_occurred ( ) ;
687
+ nodes[ 1 ] . node . timer_tick_occurred ( ) ;
688
+
689
+ let txn = nodes[ 1 ] . tx_broadcaster . txn_broadcasted . lock ( ) . unwrap ( ) ;
690
+ assert_eq ! ( txn. len( ) , 1 ) ;
691
+ assert_eq ! ( txn[ 0 ] . output. len( ) , 2 ) ;
692
+
693
+ // If we timed out we should have a P2WPKH and P2WSH output, otherwise both should be P2WPKH.
694
+ if timeout_step <= 1 {
695
+ assert ! ( ( txn[ 0 ] . output[ 0 ] . script_pubkey. len( ) == 20 +1 +1 &&
696
+ txn[ 0 ] . output[ 1 ] . script_pubkey. len( ) == 32 +1 +1 ) ||
697
+ ( txn[ 0 ] . output[ 1 ] . script_pubkey. len( ) == 20 +1 +1 &&
698
+ txn[ 0 ] . output[ 0 ] . script_pubkey. len( ) == 32 +1 +1 ) ) ;
699
+ check_closed_broadcast ! ( nodes[ 1 ] , true ) ;
700
+ check_added_monitors ! ( nodes[ 1 ] , 1 ) ;
701
+ } else {
702
+ assert_eq ! ( txn[ 0 ] . output[ 0 ] . script_pubkey. len( ) , 20 +1 +1 ) ;
703
+ assert_eq ! ( txn[ 0 ] . output[ 1 ] . script_pubkey. len( ) , 20 +1 +1 ) ;
704
+
705
+ let events = nodes[ 1 ] . node . get_and_clear_pending_msg_events ( ) ;
706
+ assert_eq ! ( events. len( ) , 1 ) ;
707
+ match events[ 0 ] {
708
+ MessageSendEvent :: BroadcastChannelUpdate { ref msg } => {
709
+ assert_eq ! ( msg. contents. flags & 2 , 2 ) ;
710
+ } ,
711
+ _ => panic ! ( "Unexpected event" ) ,
712
+ }
713
+ }
714
+ }
715
+
716
+ #[ test]
717
+ fn test_closing_signed_reinit_timeout ( ) {
718
+ do_test_closing_signed_reinit_timeout ( 0 ) ;
719
+ do_test_closing_signed_reinit_timeout ( 1 ) ;
720
+ do_test_closing_signed_reinit_timeout ( 2 ) ;
721
+ }
0 commit comments